From 1f1bc429ed7a4d591a7374f0e267b59747b177bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=B0=E6=AC=A7?= Date: Thu, 9 Aug 2018 17:20:06 +0800 Subject: [PATCH 01/12] chore: add test case for source/function of recovery.go (#1467) --- recovery_test.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/recovery_test.go b/recovery_test.go index de3b62a5..fa065b13 100644 --- a/recovery_test.go +++ b/recovery_test.go @@ -41,3 +41,23 @@ func TestPanicWithAbort(t *testing.T) { // TEST assert.Equal(t, 400, w.Code) } + +func TestSource(t *testing.T) { + bs := source(nil, 0) + assert.Equal(t, []byte("???"), bs) + + in := [][]byte{ + []byte("Hello world."), + []byte("Hi, gin.."), + } + bs = source(in, 10) + assert.Equal(t, []byte("???"), bs) + + bs = source(in, 1) + assert.Equal(t, []byte("Hello world."), bs) +} + +func TestFunction(t *testing.T) { + bs := function(1) + assert.Equal(t, []byte("???"), bs) +} From 8fc8ce047243dbbbc5eb3d01b9fd026fc3b08c82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=B0=E6=AC=A7?= Date: Fri, 10 Aug 2018 20:50:23 +0800 Subject: [PATCH 02/12] small enhance for cleanPath (#1469) from httprouter patch: https://github.com/julienschmidt/httprouter/pull/243 --- path.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/path.go b/path.go index 1c2b8498..d1f59622 100644 --- a/path.go +++ b/path.go @@ -59,11 +59,11 @@ func cleanPath(p string) string { case p[r] == '.' && p[r+1] == '/': // . element - r++ + r += 2 case p[r] == '.' && p[r+1] == '.' && (r+2 == n || p[r+2] == '/'): // .. element: remove to last / - r += 2 + r += 3 if w > 1 { // can backtrack From 7e64d32269d817b645d5d4694100a8a8ad6960cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=B0=E6=AC=A7?= Date: Sun, 12 Aug 2018 10:12:33 +0800 Subject: [PATCH 03/12] Attempt to fix #1462 (#1463) #1462 --- context_test.go | 20 ++++++++++++++++++++ test_helpers.go | 25 +------------------------ 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/context_test.go b/context_test.go index 40ae5bf8..0185507f 100644 --- a/context_test.go +++ b/context_test.go @@ -1560,6 +1560,26 @@ func TestContextRenderDataFromReader(t *testing.T) { assert.Equal(t, extraHeaders["Content-Disposition"], w.HeaderMap.Get("Content-Disposition")) } +type TestResponseRecorder struct { + *httptest.ResponseRecorder + closeChannel chan bool +} + +func (r *TestResponseRecorder) CloseNotify() <-chan bool { + return r.closeChannel +} + +func (r *TestResponseRecorder) closeClient() { + r.closeChannel <- true +} + +func CreateTestResponseRecorder() *TestResponseRecorder { + return &TestResponseRecorder{ + httptest.NewRecorder(), + make(chan bool, 1), + } +} + func TestContextStream(t *testing.T) { w := CreateTestResponseRecorder() c, _ := CreateTestContext(w) diff --git a/test_helpers.go b/test_helpers.go index 554568d9..3a7a5ddf 100644 --- a/test_helpers.go +++ b/test_helpers.go @@ -4,10 +4,7 @@ package gin -import ( - "net/http" - "net/http/httptest" -) +import "net/http" // CreateTestContext returns a fresh engine and context for testing purposes func CreateTestContext(w http.ResponseWriter) (c *Context, r *Engine) { @@ -17,23 +14,3 @@ func CreateTestContext(w http.ResponseWriter) (c *Context, r *Engine) { c.writermem.reset(w) return } - -type TestResponseRecorder struct { - *httptest.ResponseRecorder - closeChannel chan bool -} - -func (r *TestResponseRecorder) CloseNotify() <-chan bool { - return r.closeChannel -} - -func (r *TestResponseRecorder) closeClient() { - r.closeChannel <- true -} - -func CreateTestResponseRecorder() *TestResponseRecorder { - return &TestResponseRecorder{ - httptest.NewRecorder(), - make(chan bool, 1), - } -} From e5bb4f62a284426de199d68d71900fcbd1285691 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=B0=E6=AC=A7?= Date: Sun, 12 Aug 2018 21:17:57 +0800 Subject: [PATCH 04/12] chore: add return or remove else for reduce indent (#1470) --- gin.go | 69 ++++++++++++++++++++++++++------------------------ routes_test.go | 10 ++++++++ 2 files changed, 46 insertions(+), 33 deletions(-) diff --git a/gin.go b/gin.go index 3ee8018d..fc4d6564 100644 --- a/gin.go +++ b/gin.go @@ -349,38 +349,40 @@ func (engine *Engine) handleHTTPRequest(c *Context) { // Find root of the tree for the given HTTP method t := engine.trees for i, tl := 0, len(t); i < tl; i++ { - if t[i].method == httpMethod { - root := t[i].root - // Find route in tree - handlers, params, tsr := root.getValue(path, c.Params, unescape) - if handlers != nil { - c.handlers = handlers - c.Params = params - c.Next() - c.writermem.WriteHeaderNow() + if t[i].method != httpMethod { + continue + } + root := t[i].root + // Find route in tree + handlers, params, tsr := root.getValue(path, c.Params, unescape) + if handlers != nil { + c.handlers = handlers + c.Params = params + c.Next() + c.writermem.WriteHeaderNow() + return + } + if httpMethod != "CONNECT" && path != "/" { + if tsr && engine.RedirectTrailingSlash { + redirectTrailingSlash(c) return } - if httpMethod != "CONNECT" && path != "/" { - if tsr && engine.RedirectTrailingSlash { - redirectTrailingSlash(c) - return - } - if engine.RedirectFixedPath && redirectFixedPath(c, root, engine.RedirectFixedPath) { - return - } + if engine.RedirectFixedPath && redirectFixedPath(c, root, engine.RedirectFixedPath) { + return } - break } + break } if engine.HandleMethodNotAllowed { for _, tree := range engine.trees { - if tree.method != httpMethod { - if handlers, _, _ := tree.root.getValue(path, nil, unescape); handlers != nil { - c.handlers = engine.allNoMethod - serveError(c, http.StatusMethodNotAllowed, default405Body) - return - } + if tree.method == httpMethod { + continue + } + if handlers, _, _ := tree.root.getValue(path, nil, unescape); handlers != nil { + c.handlers = engine.allNoMethod + serveError(c, http.StatusMethodNotAllowed, default405Body) + return } } } @@ -393,14 +395,16 @@ var mimePlain = []string{MIMEPlain} func serveError(c *Context, code int, defaultMessage []byte) { c.writermem.status = code c.Next() - if !c.writermem.Written() { - if c.writermem.Status() == code { - c.writermem.Header()["Content-Type"] = mimePlain - c.Writer.Write(defaultMessage) - } else { - c.writermem.WriteHeaderNow() - } + if c.writermem.Written() { + return } + if c.writermem.Status() == code { + c.writermem.Header()["Content-Type"] = mimePlain + c.Writer.Write(defaultMessage) + return + } + c.writermem.WriteHeaderNow() + return } func redirectTrailingSlash(c *Context) { @@ -411,10 +415,9 @@ func redirectTrailingSlash(c *Context) { code = http.StatusTemporaryRedirect } + req.URL.Path = path + "/" if length := len(path); length > 1 && path[length-1] == '/' { req.URL.Path = path[:length-1] - } else { - req.URL.Path = path + "/" } debugPrint("redirecting request %d: %s --> %s", code, path, req.URL.String()) http.Redirect(c.Writer, req, req.URL.String(), code) diff --git a/routes_test.go b/routes_test.go index 81293907..a2389f9b 100644 --- a/routes_test.go +++ b/routes_test.go @@ -333,6 +333,16 @@ func TestRouteNotAllowedEnabled(t *testing.T) { assert.Equal(t, http.StatusTeapot, w.Code) } +func TestRouteNotAllowedEnabled2(t *testing.T) { + router := New() + router.HandleMethodNotAllowed = true + // add one methodTree to trees + router.addRoute("POST", "/", HandlersChain{func(_ *Context) {}}) + router.GET("/path2", func(c *Context) {}) + w := performRequest(router, "POST", "/path2") + assert.Equal(t, http.StatusMethodNotAllowed, w.Code) +} + func TestRouteNotAllowedDisabled(t *testing.T) { router := New() router.HandleMethodNotAllowed = false From 202db4fb117768795c0fcc909cc9c3d75b9172b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=B0=E6=AC=A7?= Date: Sun, 12 Aug 2018 21:38:07 +0800 Subject: [PATCH 05/12] improve utils code coverage (#1473) --- utils_test.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/utils_test.go b/utils_test.go index 3d019e7e..95b5de5e 100644 --- a/utils_test.go +++ b/utils_test.go @@ -5,6 +5,8 @@ package gin import ( + "bytes" + "encoding/xml" "fmt" "net/http" "testing" @@ -124,3 +126,14 @@ func TestBindMiddleware(t *testing.T) { Bind(&bindTestStruct{}) }) } + +func TestMarshalXMLforH(t *testing.T) { + h := H{ + "": "test", + } + var b bytes.Buffer + enc := xml.NewEncoder(&b) + var x xml.StartElement + e := h.MarshalXML(enc, x) + assert.Error(t, e) +} From 1ae32f3a2cfa53d1ae3e5c10a72841673bedc449 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=B0=E6=AC=A7?= Date: Sun, 12 Aug 2018 22:02:37 +0800 Subject: [PATCH 06/12] improve render code coverage (#1474) all code coverage > 99% --- render/render_test.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/render/render_test.go b/render/render_test.go index 2f728441..9e768850 100755 --- a/render/render_test.go +++ b/render/render_test.go @@ -158,6 +158,21 @@ func TestRenderJsonpJSON(t *testing.T) { assert.Equal(t, "application/javascript; charset=utf-8", w2.Header().Get("Content-Type")) } +func TestRenderJsonpJSONError2(t *testing.T) { + w := httptest.NewRecorder() + data := map[string]interface{}{ + "foo": "bar", + } + (JsonpJSON{"", data}).WriteContentType(w) + assert.Equal(t, "application/javascript; charset=utf-8", w.Header().Get("Content-Type")) + + e := (JsonpJSON{"", data}).Render(w) + assert.NoError(t, e) + + assert.Equal(t, "{\"foo\":\"bar\"}", w.Body.String()) + assert.Equal(t, "application/javascript; charset=utf-8", w.Header().Get("Content-Type")) +} + func TestRenderJsonpJSONFail(t *testing.T) { w := httptest.NewRecorder() data := make(chan int) From 61592134625e0fca1b2de7c22107a01684e8b130 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=B0=E6=AC=A7?= Date: Sun, 12 Aug 2018 23:38:31 +0800 Subject: [PATCH 07/12] unify test data (#1417) mkdir a test data dir. --- README.md | 2 +- binding/binding_body_test.go | 6 +++--- binding/binding_test.go | 14 +++++++------- debug_test.go | 2 +- examples/template/main.go | 2 +- gin_test.go | 8 ++++---- render/render_test.go | 4 ++-- .../testdata => testdata/certificate}/cert.pem | 0 .../testdata => testdata/certificate}/key.pem | 0 .../example => testdata/protoexample}/test.pb.go | 6 +++--- .../example => testdata/protoexample}/test.proto | 2 +- {fixtures/basic => testdata/template}/hello.tmpl | 0 {fixtures/basic => testdata/template}/raw.tmpl | 0 13 files changed, 23 insertions(+), 23 deletions(-) rename {fixtures/testdata => testdata/certificate}/cert.pem (100%) rename {fixtures/testdata => testdata/certificate}/key.pem (100%) rename {binding/example => testdata/protoexample}/test.pb.go (94%) rename {binding/example => testdata/protoexample}/test.proto (90%) rename {fixtures/basic => testdata/template}/hello.tmpl (100%) rename {fixtures/basic => testdata/template}/raw.tmpl (100%) diff --git a/README.md b/README.md index c2cfe2d0..bf1bbb49 100644 --- a/README.md +++ b/README.md @@ -1117,7 +1117,7 @@ func main() { router.SetFuncMap(template.FuncMap{ "formatAsDate": formatAsDate, }) - router.LoadHTMLFiles("./fixtures/basic/raw.tmpl") + router.LoadHTMLFiles("./testdata/template/raw.tmpl") router.GET("/raw", func(c *gin.Context) { c.HTML(http.StatusOK, "raw.tmpl", map[string]interface{}{ diff --git a/binding/binding_body_test.go b/binding/binding_body_test.go index c41d9f86..dfd761e1 100644 --- a/binding/binding_body_test.go +++ b/binding/binding_body_test.go @@ -5,7 +5,7 @@ import ( "io/ioutil" "testing" - "github.com/gin-gonic/gin/binding/example" + "github.com/gin-gonic/gin/testdata/protoexample" "github.com/golang/protobuf/proto" "github.com/stretchr/testify/assert" "github.com/ugorji/go/codec" @@ -55,12 +55,12 @@ func msgPackBody(t *testing.T) string { } func TestBindingBodyProto(t *testing.T) { - test := example.Test{ + test := protoexample.Test{ Label: proto.String("FOO"), } data, _ := proto.Marshal(&test) req := requestWithBody("POST", "/", string(data)) - form := example.Test{} + form := protoexample.Test{} body, _ := ioutil.ReadAll(req.Body) assert.NoError(t, ProtoBuf.BindBody(body, &form)) assert.Equal(t, test, form) diff --git a/binding/binding_test.go b/binding/binding_test.go index 936deac7..efe87669 100644 --- a/binding/binding_test.go +++ b/binding/binding_test.go @@ -14,7 +14,7 @@ import ( "testing" "time" - "github.com/gin-gonic/gin/binding/example" + "github.com/gin-gonic/gin/testdata/protoexample" "github.com/golang/protobuf/proto" "github.com/stretchr/testify/assert" "github.com/ugorji/go/codec" @@ -562,7 +562,7 @@ func TestBindingFormMultipartFail(t *testing.T) { } func TestBindingProtoBuf(t *testing.T) { - test := &example.Test{ + test := &protoexample.Test{ Label: proto.String("yes"), } data, _ := proto.Marshal(test) @@ -574,7 +574,7 @@ func TestBindingProtoBuf(t *testing.T) { } func TestBindingProtoBufFail(t *testing.T) { - test := &example.Test{ + test := &protoexample.Test{ Label: proto.String("yes"), } data, _ := proto.Marshal(test) @@ -1156,14 +1156,14 @@ func testBodyBindingFail(t *testing.T, b Binding, name, path, badPath, body, bad func testProtoBodyBinding(t *testing.T, b Binding, name, path, badPath, body, badBody string) { assert.Equal(t, name, b.Name()) - obj := example.Test{} + obj := protoexample.Test{} req := requestWithBody("POST", path, body) req.Header.Add("Content-Type", MIMEPROTOBUF) err := b.Bind(req, &obj) assert.NoError(t, err) assert.Equal(t, "yes", *obj.Label) - obj = example.Test{} + obj = protoexample.Test{} req = requestWithBody("POST", badPath, badBody) req.Header.Add("Content-Type", MIMEPROTOBUF) err = ProtoBuf.Bind(req, &obj) @@ -1179,7 +1179,7 @@ func (h hook) Read([]byte) (int, error) { func testProtoBodyBindingFail(t *testing.T, b Binding, name, path, badPath, body, badBody string) { assert.Equal(t, name, b.Name()) - obj := example.Test{} + obj := protoexample.Test{} req := requestWithBody("POST", path, body) req.Body = ioutil.NopCloser(&hook{}) @@ -1187,7 +1187,7 @@ func testProtoBodyBindingFail(t *testing.T, b Binding, name, path, badPath, body err := b.Bind(req, &obj) assert.Error(t, err) - obj = example.Test{} + obj = protoexample.Test{} req = requestWithBody("POST", badPath, badBody) req.Header.Add("Content-Type", MIMEPROTOBUF) err = ProtoBuf.Bind(req, &obj) diff --git a/debug_test.go b/debug_test.go index 440173b7..ed5a6a54 100644 --- a/debug_test.go +++ b/debug_test.go @@ -72,7 +72,7 @@ func TestDebugPrintLoadTemplate(t *testing.T) { setup(&w) defer teardown() - templ := template.Must(template.New("").Delims("{[{", "}]}").ParseGlob("./fixtures/basic/hello.tmpl")) + templ := template.Must(template.New("").Delims("{[{", "}]}").ParseGlob("./testdata/template/hello.tmpl")) debugPrintLoadTemplate(templ) assert.Regexp(t, `^\[GIN-debug\] Loaded HTML Templates \(2\): \n(\t- \n|\t- hello\.tmpl\n){2}\n`, w.String()) } diff --git a/examples/template/main.go b/examples/template/main.go index f9e611df..e20a3b98 100644 --- a/examples/template/main.go +++ b/examples/template/main.go @@ -20,7 +20,7 @@ func main() { router.SetFuncMap(template.FuncMap{ "formatAsDate": formatAsDate, }) - router.LoadHTMLFiles("../../fixtures/basic/raw.tmpl") + router.LoadHTMLFiles("../../testdata/template/raw.tmpl") router.GET("/raw", func(c *gin.Context) { c.HTML(http.StatusOK, "raw.tmpl", map[string]interface{}{ diff --git a/gin_test.go b/gin_test.go index 3ac60577..b3cab715 100644 --- a/gin_test.go +++ b/gin_test.go @@ -30,7 +30,7 @@ func setupHTMLFiles(t *testing.T, mode string, tls bool) func() { router.SetFuncMap(template.FuncMap{ "formatAsDate": formatAsDate, }) - router.LoadHTMLFiles("./fixtures/basic/hello.tmpl", "./fixtures/basic/raw.tmpl") + router.LoadHTMLFiles("./testdata/template/hello.tmpl", "./testdata/template/raw.tmpl") router.GET("/test", func(c *Context) { c.HTML(http.StatusOK, "hello.tmpl", map[string]string{"name": "world"}) }) @@ -41,7 +41,7 @@ func setupHTMLFiles(t *testing.T, mode string, tls bool) func() { }) if tls { // these files generated by `go run $GOROOT/src/crypto/tls/generate_cert.go --host 127.0.0.1` - router.RunTLS(":9999", "./fixtures/testdata/cert.pem", "./fixtures/testdata/key.pem") + router.RunTLS(":9999", "./testdata/certificate/cert.pem", "./testdata/certificate/key.pem") } else { router.Run(":8888") } @@ -59,7 +59,7 @@ func setupHTMLGlob(t *testing.T, mode string, tls bool) func() { router.SetFuncMap(template.FuncMap{ "formatAsDate": formatAsDate, }) - router.LoadHTMLGlob("./fixtures/basic/*") + router.LoadHTMLGlob("./testdata/template/*") router.GET("/test", func(c *Context) { c.HTML(http.StatusOK, "hello.tmpl", map[string]string{"name": "world"}) }) @@ -70,7 +70,7 @@ func setupHTMLGlob(t *testing.T, mode string, tls bool) func() { }) if tls { // these files generated by `go run $GOROOT/src/crypto/tls/generate_cert.go --host 127.0.0.1` - router.RunTLS(":9999", "./fixtures/testdata/cert.pem", "./fixtures/testdata/key.pem") + router.RunTLS(":9999", "./testdata/certificate/cert.pem", "./testdata/certificate/key.pem") } else { router.Run(":8888") } diff --git a/render/render_test.go b/render/render_test.go index 9e768850..8fad12b3 100755 --- a/render/render_test.go +++ b/render/render_test.go @@ -388,7 +388,7 @@ func TestRenderHTMLTemplateEmptyName(t *testing.T) { func TestRenderHTMLDebugFiles(t *testing.T) { w := httptest.NewRecorder() - htmlRender := HTMLDebug{Files: []string{"../fixtures/basic/hello.tmpl"}, + htmlRender := HTMLDebug{Files: []string{"../testdata/template/hello.tmpl"}, Glob: "", Delims: Delims{Left: "{[{", Right: "}]}"}, FuncMap: nil, @@ -407,7 +407,7 @@ func TestRenderHTMLDebugFiles(t *testing.T) { func TestRenderHTMLDebugGlob(t *testing.T) { w := httptest.NewRecorder() htmlRender := HTMLDebug{Files: nil, - Glob: "../fixtures/basic/hello*", + Glob: "../testdata/template/hello*", Delims: Delims{Left: "{[{", Right: "}]}"}, FuncMap: nil, } diff --git a/fixtures/testdata/cert.pem b/testdata/certificate/cert.pem similarity index 100% rename from fixtures/testdata/cert.pem rename to testdata/certificate/cert.pem diff --git a/fixtures/testdata/key.pem b/testdata/certificate/key.pem similarity index 100% rename from fixtures/testdata/key.pem rename to testdata/certificate/key.pem diff --git a/binding/example/test.pb.go b/testdata/protoexample/test.pb.go similarity index 94% rename from binding/example/test.pb.go rename to testdata/protoexample/test.pb.go index 3de8444f..21997ca1 100644 --- a/binding/example/test.pb.go +++ b/testdata/protoexample/test.pb.go @@ -3,7 +3,7 @@ // DO NOT EDIT! /* -Package example is a generated protocol buffer package. +Package protoexample is a generated protocol buffer package. It is generated from these files: test.proto @@ -11,7 +11,7 @@ It is generated from these files: It has these top-level messages: Test */ -package example +package protoexample import proto "github.com/golang/protobuf/proto" import math "math" @@ -109,5 +109,5 @@ func (m *Test_OptionalGroup) GetRequiredField() string { } func init() { - proto.RegisterEnum("example.FOO", FOO_name, FOO_value) + proto.RegisterEnum("protoexample.FOO", FOO_name, FOO_value) } diff --git a/binding/example/test.proto b/testdata/protoexample/test.proto similarity index 90% rename from binding/example/test.proto rename to testdata/protoexample/test.proto index 8ee9800a..3e734287 100644 --- a/binding/example/test.proto +++ b/testdata/protoexample/test.proto @@ -1,4 +1,4 @@ -package example; +package protoexample; enum FOO {X=17;}; diff --git a/fixtures/basic/hello.tmpl b/testdata/template/hello.tmpl similarity index 100% rename from fixtures/basic/hello.tmpl rename to testdata/template/hello.tmpl diff --git a/fixtures/basic/raw.tmpl b/testdata/template/raw.tmpl similarity index 100% rename from fixtures/basic/raw.tmpl rename to testdata/template/raw.tmpl From 8aef947f6eeeb47872c2e5910d20258cc6ccf375 Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 12 Aug 2018 22:54:22 +0200 Subject: [PATCH 08/12] docs: remove double negative in README.md (#1480) "not match neither" means that it will match. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bf1bbb49..28598baf 100644 --- a/README.md +++ b/README.md @@ -238,7 +238,7 @@ func main() { func main() { router := gin.Default() - // This handler will match /user/john but will not match neither /user/ or /user + // This handler will match /user/john but will not match /user/ or /user router.GET("/user/:name", func(c *gin.Context) { name := c.Param("name") c.String(http.StatusOK, "Hello %s", name) From f45c928a156e60e521dceea99a183f9c9cf5b2de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=B0=E6=AC=A7?= Date: Tue, 14 Aug 2018 09:51:56 +0800 Subject: [PATCH 09/12] chore: use http.Status* instead of hard code (#1482) --- auth_test.go | 12 +-- benchmarks_test.go | 6 +- context_test.go | 153 ++++++++++++++------------- examples/basic/main.go | 10 +- examples/basic/main_test.go | 2 +- examples/favicon/main.go | 4 +- examples/http2/main.go | 3 +- examples/realtime-advanced/routes.go | 11 +- examples/realtime-chat/main.go | 5 +- githubapi_test.go | 2 +- logger.go | 7 +- logger_test.go | 17 +-- middleware_test.go | 33 +++--- recovery_test.go | 7 +- render/redirect.go | 2 + render/render_test.go | 4 +- response_writer_test.go | 20 ++-- routergroup_test.go | 7 +- routes_test.go | 88 +++++++-------- utils_test.go | 8 +- 20 files changed, 209 insertions(+), 192 deletions(-) diff --git a/auth_test.go b/auth_test.go index dc8523b0..ab7e94be 100644 --- a/auth_test.go +++ b/auth_test.go @@ -93,7 +93,7 @@ func TestBasicAuthSucceed(t *testing.T) { router := New() router.Use(BasicAuth(accounts)) router.GET("/login", func(c *Context) { - c.String(200, c.MustGet(AuthUserKey).(string)) + c.String(http.StatusOK, c.MustGet(AuthUserKey).(string)) }) w := httptest.NewRecorder() @@ -101,7 +101,7 @@ func TestBasicAuthSucceed(t *testing.T) { req.Header.Set("Authorization", authorizationHeader("admin", "password")) router.ServeHTTP(w, req) - assert.Equal(t, 200, w.Code) + assert.Equal(t, http.StatusOK, w.Code) assert.Equal(t, "admin", w.Body.String()) } @@ -112,7 +112,7 @@ func TestBasicAuth401(t *testing.T) { router.Use(BasicAuth(accounts)) router.GET("/login", func(c *Context) { called = true - c.String(200, c.MustGet(AuthUserKey).(string)) + c.String(http.StatusOK, c.MustGet(AuthUserKey).(string)) }) w := httptest.NewRecorder() @@ -121,7 +121,7 @@ func TestBasicAuth401(t *testing.T) { router.ServeHTTP(w, req) assert.False(t, called) - assert.Equal(t, 401, w.Code) + assert.Equal(t, http.StatusUnauthorized, w.Code) assert.Equal(t, "Basic realm=\"Authorization Required\"", w.HeaderMap.Get("WWW-Authenticate")) } @@ -132,7 +132,7 @@ func TestBasicAuth401WithCustomRealm(t *testing.T) { router.Use(BasicAuthForRealm(accounts, "My Custom \"Realm\"")) router.GET("/login", func(c *Context) { called = true - c.String(200, c.MustGet(AuthUserKey).(string)) + c.String(http.StatusOK, c.MustGet(AuthUserKey).(string)) }) w := httptest.NewRecorder() @@ -141,6 +141,6 @@ func TestBasicAuth401WithCustomRealm(t *testing.T) { router.ServeHTTP(w, req) assert.False(t, called) - assert.Equal(t, 401, w.Code) + assert.Equal(t, http.StatusUnauthorized, w.Code) assert.Equal(t, "Basic realm=\"My Custom \\\"Realm\\\"\"", w.HeaderMap.Get("WWW-Authenticate")) } diff --git a/benchmarks_test.go b/benchmarks_test.go index e7970034..0b3f82df 100644 --- a/benchmarks_test.go +++ b/benchmarks_test.go @@ -54,7 +54,7 @@ func BenchmarkOneRouteJSON(B *testing.B) { Status string `json:"status"` }{"ok"} router.GET("/json", func(c *Context) { - c.JSON(200, data) + c.JSON(http.StatusOK, data) }) runRequest(B, router, "GET", "/json") } @@ -66,7 +66,7 @@ func BenchmarkOneRouteHTML(B *testing.B) { router.SetHTMLTemplate(t) router.GET("/html", func(c *Context) { - c.HTML(200, "index", "hola") + c.HTML(http.StatusOK, "index", "hola") }) runRequest(B, router, "GET", "/html") } @@ -82,7 +82,7 @@ func BenchmarkOneRouteSet(B *testing.B) { func BenchmarkOneRouteString(B *testing.B) { router := New() router.GET("/text", func(c *Context) { - c.String(200, "this is a plain text") + c.String(http.StatusOK, "this is a plain text") }) runRequest(B, router, "GET", "/text") } diff --git a/context_test.go b/context_test.go index 0185507f..99d5267d 100644 --- a/context_test.go +++ b/context_test.go @@ -9,6 +9,7 @@ import ( "errors" "fmt" "html/template" + "io" "mime/multipart" "net/http" "net/http/httptest" @@ -21,7 +22,6 @@ import ( "github.com/gin-gonic/gin/binding" "github.com/stretchr/testify/assert" "golang.org/x/net/context" - "io" ) var _ context.Context = &Context{} @@ -585,10 +585,11 @@ func TestContextGetCookie(t *testing.T) { } func TestContextBodyAllowedForStatus(t *testing.T) { + // todo(thinkerou): go1.6 not support StatusProcessing assert.False(t, false, bodyAllowedForStatus(102)) - assert.False(t, false, bodyAllowedForStatus(204)) - assert.False(t, false, bodyAllowedForStatus(304)) - assert.True(t, true, bodyAllowedForStatus(500)) + assert.False(t, false, bodyAllowedForStatus(http.StatusNoContent)) + assert.False(t, false, bodyAllowedForStatus(http.StatusNotModified)) + assert.True(t, true, bodyAllowedForStatus(http.StatusInternalServerError)) } type TestPanicRender struct { @@ -619,9 +620,9 @@ func TestContextRenderJSON(t *testing.T) { w := httptest.NewRecorder() c, _ := CreateTestContext(w) - c.JSON(201, H{"foo": "bar"}) + c.JSON(http.StatusCreated, H{"foo": "bar"}) - assert.Equal(t, 201, w.Code) + assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "{\"foo\":\"bar\"}", w.Body.String()) assert.Equal(t, "application/json; charset=utf-8", w.HeaderMap.Get("Content-Type")) } @@ -633,9 +634,9 @@ func TestContextRenderJSONP(t *testing.T) { c, _ := CreateTestContext(w) c.Request, _ = http.NewRequest("GET", "http://example.com/?callback=x", nil) - c.JSONP(201, H{"foo": "bar"}) + c.JSONP(http.StatusCreated, H{"foo": "bar"}) - assert.Equal(t, 201, w.Code) + assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "x({\"foo\":\"bar\"})", w.Body.String()) assert.Equal(t, "application/javascript; charset=utf-8", w.HeaderMap.Get("Content-Type")) } @@ -647,9 +648,9 @@ func TestContextRenderJSONPWithoutCallback(t *testing.T) { c, _ := CreateTestContext(w) c.Request, _ = http.NewRequest("GET", "http://example.com", nil) - c.JSONP(201, H{"foo": "bar"}) + c.JSONP(http.StatusCreated, H{"foo": "bar"}) - assert.Equal(t, 201, w.Code) + assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "{\"foo\":\"bar\"}", w.Body.String()) assert.Equal(t, "application/json; charset=utf-8", w.HeaderMap.Get("Content-Type")) } @@ -659,9 +660,9 @@ func TestContextRenderNoContentJSON(t *testing.T) { w := httptest.NewRecorder() c, _ := CreateTestContext(w) - c.JSON(204, H{"foo": "bar"}) + c.JSON(http.StatusNoContent, H{"foo": "bar"}) - assert.Equal(t, 204, w.Code) + assert.Equal(t, http.StatusNoContent, w.Code) assert.Empty(t, w.Body.String()) assert.Equal(t, "application/json; charset=utf-8", w.HeaderMap.Get("Content-Type")) } @@ -673,9 +674,9 @@ func TestContextRenderAPIJSON(t *testing.T) { c, _ := CreateTestContext(w) c.Header("Content-Type", "application/vnd.api+json") - c.JSON(201, H{"foo": "bar"}) + c.JSON(http.StatusCreated, H{"foo": "bar"}) - assert.Equal(t, 201, w.Code) + assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "{\"foo\":\"bar\"}", w.Body.String()) assert.Equal(t, "application/vnd.api+json", w.HeaderMap.Get("Content-Type")) } @@ -686,9 +687,9 @@ func TestContextRenderNoContentAPIJSON(t *testing.T) { c, _ := CreateTestContext(w) c.Header("Content-Type", "application/vnd.api+json") - c.JSON(204, H{"foo": "bar"}) + c.JSON(http.StatusNoContent, H{"foo": "bar"}) - assert.Equal(t, 204, w.Code) + assert.Equal(t, http.StatusNoContent, w.Code) assert.Empty(t, w.Body.String()) assert.Equal(t, w.HeaderMap.Get("Content-Type"), "application/vnd.api+json") } @@ -699,9 +700,9 @@ func TestContextRenderIndentedJSON(t *testing.T) { w := httptest.NewRecorder() c, _ := CreateTestContext(w) - c.IndentedJSON(201, H{"foo": "bar", "bar": "foo", "nested": H{"foo": "bar"}}) + c.IndentedJSON(http.StatusCreated, H{"foo": "bar", "bar": "foo", "nested": H{"foo": "bar"}}) - assert.Equal(t, 201, w.Code) + 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.HeaderMap.Get("Content-Type")) } @@ -711,9 +712,9 @@ func TestContextRenderNoContentIndentedJSON(t *testing.T) { w := httptest.NewRecorder() c, _ := CreateTestContext(w) - c.IndentedJSON(204, H{"foo": "bar", "bar": "foo", "nested": H{"foo": "bar"}}) + c.IndentedJSON(http.StatusNoContent, H{"foo": "bar", "bar": "foo", "nested": H{"foo": "bar"}}) - assert.Equal(t, 204, w.Code) + assert.Equal(t, http.StatusNoContent, w.Code) assert.Empty(t, w.Body.String()) assert.Equal(t, "application/json; charset=utf-8", w.HeaderMap.Get("Content-Type")) } @@ -725,9 +726,9 @@ func TestContextRenderSecureJSON(t *testing.T) { c, router := CreateTestContext(w) router.SecureJsonPrefix("&&&START&&&") - c.SecureJSON(201, []string{"foo", "bar"}) + c.SecureJSON(http.StatusCreated, []string{"foo", "bar"}) - assert.Equal(t, 201, w.Code) + assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "&&&START&&&[\"foo\",\"bar\"]", w.Body.String()) assert.Equal(t, "application/json; charset=utf-8", w.HeaderMap.Get("Content-Type")) } @@ -737,9 +738,9 @@ func TestContextRenderNoContentSecureJSON(t *testing.T) { w := httptest.NewRecorder() c, _ := CreateTestContext(w) - c.SecureJSON(204, []string{"foo", "bar"}) + c.SecureJSON(http.StatusNoContent, []string{"foo", "bar"}) - assert.Equal(t, 204, w.Code) + assert.Equal(t, http.StatusNoContent, w.Code) assert.Empty(t, w.Body.String()) assert.Equal(t, "application/json; charset=utf-8", w.HeaderMap.Get("Content-Type")) } @@ -764,9 +765,9 @@ func TestContextRenderHTML(t *testing.T) { templ := template.Must(template.New("t").Parse(`Hello {{.name}}`)) router.SetHTMLTemplate(templ) - c.HTML(201, "t", H{"name": "alexandernyquist"}) + c.HTML(http.StatusCreated, "t", H{"name": "alexandernyquist"}) - assert.Equal(t, 201, w.Code) + assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "Hello alexandernyquist", w.Body.String()) assert.Equal(t, "text/html; charset=utf-8", w.HeaderMap.Get("Content-Type")) } @@ -788,9 +789,9 @@ 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", b.String()) - c.HTML(201, "t", H{"name": "alexandernyquist"}) + c.HTML(http.StatusCreated, "t", H{"name": "alexandernyquist"}) - assert.Equal(t, 201, w.Code) + assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "Hello alexandernyquist", w.Body.String()) assert.Equal(t, "text/html; charset=utf-8", w.HeaderMap.Get("Content-Type")) } @@ -802,9 +803,9 @@ func TestContextRenderNoContentHTML(t *testing.T) { templ := template.Must(template.New("t").Parse(`Hello {{.name}}`)) router.SetHTMLTemplate(templ) - c.HTML(204, "t", H{"name": "alexandernyquist"}) + c.HTML(http.StatusNoContent, "t", H{"name": "alexandernyquist"}) - assert.Equal(t, 204, w.Code) + assert.Equal(t, http.StatusNoContent, w.Code) assert.Empty(t, w.Body.String()) assert.Equal(t, "text/html; charset=utf-8", w.HeaderMap.Get("Content-Type")) } @@ -815,9 +816,9 @@ func TestContextRenderXML(t *testing.T) { w := httptest.NewRecorder() c, _ := CreateTestContext(w) - c.XML(201, H{"foo": "bar"}) + c.XML(http.StatusCreated, H{"foo": "bar"}) - assert.Equal(t, 201, w.Code) + assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "bar", w.Body.String()) assert.Equal(t, "application/xml; charset=utf-8", w.HeaderMap.Get("Content-Type")) } @@ -827,9 +828,9 @@ func TestContextRenderNoContentXML(t *testing.T) { w := httptest.NewRecorder() c, _ := CreateTestContext(w) - c.XML(204, H{"foo": "bar"}) + c.XML(http.StatusNoContent, H{"foo": "bar"}) - assert.Equal(t, 204, w.Code) + assert.Equal(t, http.StatusNoContent, w.Code) assert.Empty(t, w.Body.String()) assert.Equal(t, "application/xml; charset=utf-8", w.HeaderMap.Get("Content-Type")) } @@ -840,9 +841,9 @@ func TestContextRenderString(t *testing.T) { w := httptest.NewRecorder() c, _ := CreateTestContext(w) - c.String(201, "test %s %d", "string", 2) + c.String(http.StatusCreated, "test %s %d", "string", 2) - assert.Equal(t, 201, w.Code) + assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "test string 2", w.Body.String()) assert.Equal(t, "text/plain; charset=utf-8", w.HeaderMap.Get("Content-Type")) } @@ -852,9 +853,9 @@ func TestContextRenderNoContentString(t *testing.T) { w := httptest.NewRecorder() c, _ := CreateTestContext(w) - c.String(204, "test %s %d", "string", 2) + c.String(http.StatusNoContent, "test %s %d", "string", 2) - assert.Equal(t, 204, w.Code) + assert.Equal(t, http.StatusNoContent, w.Code) assert.Empty(t, w.Body.String()) assert.Equal(t, "text/plain; charset=utf-8", w.HeaderMap.Get("Content-Type")) } @@ -866,9 +867,9 @@ func TestContextRenderHTMLString(t *testing.T) { c, _ := CreateTestContext(w) c.Header("Content-Type", "text/html; charset=utf-8") - c.String(201, "%s %d", "string", 3) + c.String(http.StatusCreated, "%s %d", "string", 3) - assert.Equal(t, 201, w.Code) + assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "string 3", w.Body.String()) assert.Equal(t, "text/html; charset=utf-8", w.HeaderMap.Get("Content-Type")) } @@ -879,9 +880,9 @@ func TestContextRenderNoContentHTMLString(t *testing.T) { c, _ := CreateTestContext(w) c.Header("Content-Type", "text/html; charset=utf-8") - c.String(204, "%s %d", "string", 3) + c.String(http.StatusNoContent, "%s %d", "string", 3) - assert.Equal(t, 204, w.Code) + assert.Equal(t, http.StatusNoContent, w.Code) assert.Empty(t, w.Body.String()) assert.Equal(t, "text/html; charset=utf-8", w.HeaderMap.Get("Content-Type")) } @@ -892,9 +893,9 @@ func TestContextRenderData(t *testing.T) { w := httptest.NewRecorder() c, _ := CreateTestContext(w) - c.Data(201, "text/csv", []byte(`foo,bar`)) + c.Data(http.StatusCreated, "text/csv", []byte(`foo,bar`)) - assert.Equal(t, 201, w.Code) + assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "foo,bar", w.Body.String()) assert.Equal(t, "text/csv", w.HeaderMap.Get("Content-Type")) } @@ -904,9 +905,9 @@ func TestContextRenderNoContentData(t *testing.T) { w := httptest.NewRecorder() c, _ := CreateTestContext(w) - c.Data(204, "text/csv", []byte(`foo,bar`)) + c.Data(http.StatusNoContent, "text/csv", []byte(`foo,bar`)) - assert.Equal(t, 204, w.Code) + assert.Equal(t, http.StatusNoContent, w.Code) assert.Empty(t, w.Body.String()) assert.Equal(t, "text/csv", w.HeaderMap.Get("Content-Type")) } @@ -935,7 +936,7 @@ func TestContextRenderFile(t *testing.T) { c.Request, _ = http.NewRequest("GET", "/", nil) c.File("./gin.go") - assert.Equal(t, 200, w.Code) + assert.Equal(t, http.StatusOK, w.Code) assert.Contains(t, w.Body.String(), "func New() *Engine {") assert.Equal(t, "text/plain; charset=utf-8", w.HeaderMap.Get("Content-Type")) } @@ -946,9 +947,9 @@ func TestContextRenderYAML(t *testing.T) { w := httptest.NewRecorder() c, _ := CreateTestContext(w) - c.YAML(201, H{"foo": "bar"}) + c.YAML(http.StatusCreated, H{"foo": "bar"}) - assert.Equal(t, 201, w.Code) + assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "foo: bar\n", w.Body.String()) assert.Equal(t, "application/x-yaml; charset=utf-8", w.HeaderMap.Get("Content-Type")) } @@ -978,9 +979,9 @@ func TestContextRenderRedirectWithRelativePath(t *testing.T) { assert.Panics(t, func() { c.Redirect(299, "/new_path") }) assert.Panics(t, func() { c.Redirect(309, "/new_path") }) - c.Redirect(301, "/path") + c.Redirect(http.StatusMovedPermanently, "/path") c.Writer.WriteHeaderNow() - assert.Equal(t, 301, w.Code) + assert.Equal(t, http.StatusMovedPermanently, w.Code) assert.Equal(t, "/path", w.Header().Get("Location")) } @@ -989,10 +990,10 @@ func TestContextRenderRedirectWithAbsolutePath(t *testing.T) { c, _ := CreateTestContext(w) c.Request, _ = http.NewRequest("POST", "http://example.com", nil) - c.Redirect(302, "http://google.com") + c.Redirect(http.StatusFound, "http://google.com") c.Writer.WriteHeaderNow() - assert.Equal(t, 302, w.Code) + assert.Equal(t, http.StatusFound, w.Code) assert.Equal(t, "http://google.com", w.Header().Get("Location")) } @@ -1001,21 +1002,23 @@ func TestContextRenderRedirectWith201(t *testing.T) { c, _ := CreateTestContext(w) c.Request, _ = http.NewRequest("POST", "http://example.com", nil) - c.Redirect(201, "/resource") + c.Redirect(http.StatusCreated, "/resource") c.Writer.WriteHeaderNow() - assert.Equal(t, 201, w.Code) + assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "/resource", w.Header().Get("Location")) } func TestContextRenderRedirectAll(t *testing.T) { c, _ := CreateTestContext(httptest.NewRecorder()) c.Request, _ = http.NewRequest("POST", "http://example.com", nil) - assert.Panics(t, func() { c.Redirect(200, "/resource") }) - assert.Panics(t, func() { c.Redirect(202, "/resource") }) + 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(300, "/resource") }) + assert.NotPanics(t, func() { c.Redirect(http.StatusMultipleChoices, "/resource") }) + // todo(thinkerou): go1.6 not support StatusPermanentRedirect(308) + // when we upgrade go version we can use http.StatusPermanentRedirect assert.NotPanics(t, func() { c.Redirect(308, "/resource") }) } @@ -1024,12 +1027,12 @@ func TestContextNegotiationWithJSON(t *testing.T) { c, _ := CreateTestContext(w) c.Request, _ = http.NewRequest("POST", "", nil) - c.Negotiate(200, Negotiate{ + c.Negotiate(http.StatusOK, Negotiate{ Offered: []string{MIMEJSON, MIMEXML}, Data: H{"foo": "bar"}, }) - assert.Equal(t, 200, w.Code) + assert.Equal(t, http.StatusOK, w.Code) assert.Equal(t, "{\"foo\":\"bar\"}", w.Body.String()) assert.Equal(t, "application/json; charset=utf-8", w.HeaderMap.Get("Content-Type")) } @@ -1039,12 +1042,12 @@ func TestContextNegotiationWithXML(t *testing.T) { c, _ := CreateTestContext(w) c.Request, _ = http.NewRequest("POST", "", nil) - c.Negotiate(200, Negotiate{ + c.Negotiate(http.StatusOK, Negotiate{ Offered: []string{MIMEXML, MIMEJSON}, Data: H{"foo": "bar"}, }) - assert.Equal(t, 200, w.Code) + assert.Equal(t, http.StatusOK, w.Code) assert.Equal(t, "bar", w.Body.String()) assert.Equal(t, "application/xml; charset=utf-8", w.HeaderMap.Get("Content-Type")) } @@ -1056,13 +1059,13 @@ func TestContextNegotiationWithHTML(t *testing.T) { templ := template.Must(template.New("t").Parse(`Hello {{.name}}`)) router.SetHTMLTemplate(templ) - c.Negotiate(200, Negotiate{ + c.Negotiate(http.StatusOK, Negotiate{ Offered: []string{MIMEHTML}, Data: H{"name": "gin"}, HTMLName: "t", }) - assert.Equal(t, 200, w.Code) + assert.Equal(t, http.StatusOK, w.Code) assert.Equal(t, "Hello gin", w.Body.String()) assert.Equal(t, "text/html; charset=utf-8", w.HeaderMap.Get("Content-Type")) } @@ -1072,11 +1075,11 @@ func TestContextNegotiationNotSupport(t *testing.T) { c, _ := CreateTestContext(w) c.Request, _ = http.NewRequest("POST", "", nil) - c.Negotiate(200, Negotiate{ + c.Negotiate(http.StatusOK, Negotiate{ Offered: []string{MIMEPOSTForm}, }) - assert.Equal(t, 406, w.Code) + assert.Equal(t, http.StatusNotAcceptable, w.Code) assert.Equal(t, c.index, abortIndex) assert.True(t, c.IsAborted()) } @@ -1134,11 +1137,11 @@ func TestContextAbortWithStatus(t *testing.T) { c, _ := CreateTestContext(w) c.index = 4 - c.AbortWithStatus(401) + c.AbortWithStatus(http.StatusUnauthorized) assert.Equal(t, abortIndex, c.index) - assert.Equal(t, 401, c.Writer.Status()) - assert.Equal(t, 401, w.Code) + assert.Equal(t, http.StatusUnauthorized, c.Writer.Status()) + assert.Equal(t, http.StatusUnauthorized, w.Code) assert.True(t, c.IsAborted()) } @@ -1156,11 +1159,11 @@ func TestContextAbortWithStatusJSON(t *testing.T) { in.Bar = "barValue" in.Foo = "fooValue" - c.AbortWithStatusJSON(415, in) + c.AbortWithStatusJSON(http.StatusUnsupportedMediaType, in) assert.Equal(t, abortIndex, c.index) - assert.Equal(t, 415, c.Writer.Status()) - assert.Equal(t, 415, w.Code) + assert.Equal(t, http.StatusUnsupportedMediaType, c.Writer.Status()) + assert.Equal(t, http.StatusUnsupportedMediaType, w.Code) assert.True(t, c.IsAborted()) contentType := w.Header().Get("Content-Type") @@ -1223,9 +1226,9 @@ func TestContextAbortWithError(t *testing.T) { w := httptest.NewRecorder() c, _ := CreateTestContext(w) - c.AbortWithError(401, errors.New("bad input")).SetMeta("some input") + c.AbortWithError(http.StatusUnauthorized, errors.New("bad input")).SetMeta("some input") - assert.Equal(t, 401, w.Code) + assert.Equal(t, http.StatusUnauthorized, w.Code) assert.Equal(t, abortIndex, c.index) assert.True(t, c.IsAborted()) } @@ -1333,7 +1336,7 @@ func TestContextBadAutoBind(t *testing.T) { assert.Empty(t, obj.Bar) assert.Empty(t, obj.Foo) - assert.Equal(t, 400, w.Code) + assert.Equal(t, http.StatusBadRequest, w.Code) assert.True(t, c.IsAborted()) } diff --git a/examples/basic/main.go b/examples/basic/main.go index 473c6a09..48fa7bba 100644 --- a/examples/basic/main.go +++ b/examples/basic/main.go @@ -1,6 +1,8 @@ package main import ( + "net/http" + "github.com/gin-gonic/gin" ) @@ -13,7 +15,7 @@ func setupRouter() *gin.Engine { // Ping test r.GET("/ping", func(c *gin.Context) { - c.String(200, "pong") + c.String(http.StatusOK, "pong") }) // Get user value @@ -21,9 +23,9 @@ func setupRouter() *gin.Engine { user := c.Params.ByName("name") value, ok := DB[user] if ok { - c.JSON(200, gin.H{"user": user, "value": value}) + c.JSON(http.StatusOK, gin.H{"user": user, "value": value}) } else { - c.JSON(200, gin.H{"user": user, "status": "no value"}) + c.JSON(http.StatusOK, gin.H{"user": user, "status": "no value"}) } }) @@ -49,7 +51,7 @@ func setupRouter() *gin.Engine { if c.Bind(&json) == nil { DB[user] = json.Value - c.JSON(200, gin.H{"status": "ok"}) + c.JSON(http.StatusOK, gin.H{"status": "ok"}) } }) diff --git a/examples/basic/main_test.go b/examples/basic/main_test.go index 61203d66..5eb85240 100644 --- a/examples/basic/main_test.go +++ b/examples/basic/main_test.go @@ -15,6 +15,6 @@ func TestPingRoute(t *testing.T) { req, _ := http.NewRequest("GET", "/ping", nil) router.ServeHTTP(w, req) - assert.Equal(t, 200, w.Code) + assert.Equal(t, http.StatusOK, w.Code) assert.Equal(t, "pong", w.Body.String()) } diff --git a/examples/favicon/main.go b/examples/favicon/main.go index 5ad39331..d32ca098 100644 --- a/examples/favicon/main.go +++ b/examples/favicon/main.go @@ -1,6 +1,8 @@ package main import ( + "net/http" + "github.com/gin-gonic/gin" "github.com/thinkerou/favicon" ) @@ -9,7 +11,7 @@ func main() { app := gin.Default() app.Use(favicon.New("./favicon.ico")) app.GET("/ping", func(c *gin.Context) { - c.String(200, "Hello favicon.") + c.String(http.StatusOK, "Hello favicon.") }) app.Run(":8080") } diff --git a/examples/http2/main.go b/examples/http2/main.go index 07df01e2..6598a4c9 100644 --- a/examples/http2/main.go +++ b/examples/http2/main.go @@ -3,6 +3,7 @@ package main import ( "html/template" "log" + "net/http" "os" "github.com/gin-gonic/gin" @@ -27,7 +28,7 @@ func main() { r.SetHTMLTemplate(html) r.GET("/welcome", func(c *gin.Context) { - c.HTML(200, "https", gin.H{ + c.HTML(http.StatusOK, "https", gin.H{ "status": "success", }) }) diff --git a/examples/realtime-advanced/routes.go b/examples/realtime-advanced/routes.go index 86da9bea..03c69910 100644 --- a/examples/realtime-advanced/routes.go +++ b/examples/realtime-advanced/routes.go @@ -4,6 +4,7 @@ import ( "fmt" "html" "io" + "net/http" "strings" "time" @@ -21,12 +22,12 @@ func rateLimit(c *gin.Context) { fmt.Println("ip blocked") } c.Abort() - c.String(503, "you were automatically banned :)") + c.String(http.StatusServiceUnavailable, "you were automatically banned :)") } } func index(c *gin.Context) { - c.Redirect(301, "/room/hn") + c.Redirect(http.StatusMovedPermanently, "/room/hn") } func roomGET(c *gin.Context) { @@ -38,7 +39,7 @@ func roomGET(c *gin.Context) { if len(nick) > 13 { nick = nick[0:12] + "..." } - c.HTML(200, "room_login.templ.html", gin.H{ + c.HTML(http.StatusOK, "room_login.templ.html", gin.H{ "roomid": roomid, "nick": nick, "timestamp": time.Now().Unix(), @@ -55,7 +56,7 @@ func roomPOST(c *gin.Context) { validMessage := len(message) > 1 && len(message) < 200 validNick := len(nick) > 1 && len(nick) < 14 if !validMessage || !validNick { - c.JSON(400, gin.H{ + c.JSON(http.StatusBadRequest, gin.H{ "status": "failed", "error": "the message or nickname is too long", }) @@ -68,7 +69,7 @@ func roomPOST(c *gin.Context) { } messages.Add("inbound", 1) room(roomid).Submit(post) - c.JSON(200, post) + c.JSON(http.StatusOK, post) } func streamRoom(c *gin.Context) { diff --git a/examples/realtime-chat/main.go b/examples/realtime-chat/main.go index e4b55a0f..5741fcba 100644 --- a/examples/realtime-chat/main.go +++ b/examples/realtime-chat/main.go @@ -4,6 +4,7 @@ import ( "fmt" "io" "math/rand" + "net/http" "github.com/gin-gonic/gin" ) @@ -34,7 +35,7 @@ func stream(c *gin.Context) { func roomGET(c *gin.Context) { roomid := c.Param("roomid") userid := fmt.Sprint(rand.Int31()) - c.HTML(200, "chat_room", gin.H{ + c.HTML(http.StatusOK, "chat_room", gin.H{ "roomid": roomid, "userid": userid, }) @@ -46,7 +47,7 @@ func roomPOST(c *gin.Context) { message := c.PostForm("message") room(roomid).Submit(userid + ": " + message) - c.JSON(200, gin.H{ + c.JSON(http.StatusOK, gin.H{ "status": "success", "message": message, }) diff --git a/githubapi_test.go b/githubapi_test.go index a08c264d..f631035d 100644 --- a/githubapi_test.go +++ b/githubapi_test.go @@ -293,7 +293,7 @@ func githubConfigRouter(router *Engine) { for _, param := range c.Params { output[param.Key] = param.Value } - c.JSON(200, output) + c.JSON(http.StatusOK, output) }) } } diff --git a/logger.go b/logger.go index c679c787..1a8df601 100644 --- a/logger.go +++ b/logger.go @@ -7,6 +7,7 @@ package gin import ( "fmt" "io" + "net/http" "os" "time" @@ -118,11 +119,11 @@ func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc { func colorForStatus(code int) string { switch { - case code >= 200 && code < 300: + case code >= http.StatusOK && code < http.StatusMultipleChoices: return green - case code >= 300 && code < 400: + case code >= http.StatusMultipleChoices && code < http.StatusBadRequest: return white - case code >= 400 && code < 500: + case code >= http.StatusBadRequest && code < http.StatusInternalServerError: return yellow default: return red diff --git a/logger_test.go b/logger_test.go index 74a9659c..7dbbf7b1 100644 --- a/logger_test.go +++ b/logger_test.go @@ -7,6 +7,7 @@ package gin import ( "bytes" "errors" + "net/http" "testing" "github.com/stretchr/testify/assert" @@ -93,9 +94,9 @@ func TestColorForMethod(t *testing.T) { } func TestColorForStatus(t *testing.T) { - assert.Equal(t, string([]byte{27, 91, 57, 55, 59, 52, 50, 109}), colorForStatus(200), "2xx should be green") - assert.Equal(t, string([]byte{27, 91, 57, 48, 59, 52, 55, 109}), colorForStatus(301), "3xx should be white") - assert.Equal(t, string([]byte{27, 91, 57, 55, 59, 52, 51, 109}), colorForStatus(404), "4xx should be yellow") + assert.Equal(t, string([]byte{27, 91, 57, 55, 59, 52, 50, 109}), colorForStatus(http.StatusOK), "2xx should be green") + assert.Equal(t, string([]byte{27, 91, 57, 48, 59, 52, 55, 109}), colorForStatus(http.StatusMovedPermanently), "3xx should be white") + assert.Equal(t, string([]byte{27, 91, 57, 55, 59, 52, 51, 109}), colorForStatus(http.StatusNotFound), "4xx should be yellow") assert.Equal(t, string([]byte{27, 91, 57, 55, 59, 52, 49, 109}), colorForStatus(2), "other things should be red") } @@ -106,23 +107,23 @@ func TestErrorLogger(t *testing.T) { c.Error(errors.New("this is an error")) }) router.GET("/abort", func(c *Context) { - c.AbortWithError(401, errors.New("no authorized")) + c.AbortWithError(http.StatusUnauthorized, errors.New("no authorized")) }) router.GET("/print", func(c *Context) { c.Error(errors.New("this is an error")) - c.String(500, "hola!") + c.String(http.StatusInternalServerError, "hola!") }) w := performRequest(router, "GET", "/error") - assert.Equal(t, 200, w.Code) + assert.Equal(t, http.StatusOK, w.Code) assert.Equal(t, "{\"error\":\"this is an error\"}", w.Body.String()) w = performRequest(router, "GET", "/abort") - assert.Equal(t, 401, w.Code) + assert.Equal(t, http.StatusUnauthorized, w.Code) assert.Equal(t, "{\"error\":\"no authorized\"}", w.Body.String()) w = performRequest(router, "GET", "/print") - assert.Equal(t, 500, w.Code) + assert.Equal(t, http.StatusInternalServerError, w.Code) assert.Equal(t, "hola!{\"error\":\"this is an error\"}", w.Body.String()) } diff --git a/middleware_test.go b/middleware_test.go index aa6a37a8..983ad933 100644 --- a/middleware_test.go +++ b/middleware_test.go @@ -6,6 +6,7 @@ package gin import ( "errors" + "net/http" "strings" "testing" @@ -37,7 +38,7 @@ func TestMiddlewareGeneralCase(t *testing.T) { w := performRequest(router, "GET", "/") // TEST - assert.Equal(t, 200, w.Code) + assert.Equal(t, http.StatusOK, w.Code) assert.Equal(t, "ACDB", signature) } @@ -73,7 +74,7 @@ func TestMiddlewareNoRoute(t *testing.T) { w := performRequest(router, "GET", "/") // TEST - assert.Equal(t, 404, w.Code) + assert.Equal(t, http.StatusNotFound, w.Code) assert.Equal(t, "ACEGHFDB", signature) } @@ -110,7 +111,7 @@ func TestMiddlewareNoMethodEnabled(t *testing.T) { w := performRequest(router, "GET", "/") // TEST - assert.Equal(t, 405, w.Code) + assert.Equal(t, http.StatusMethodNotAllowed, w.Code) assert.Equal(t, "ACEGHFDB", signature) } @@ -147,7 +148,7 @@ func TestMiddlewareNoMethodDisabled(t *testing.T) { w := performRequest(router, "GET", "/") // TEST - assert.Equal(t, 404, w.Code) + assert.Equal(t, http.StatusNotFound, w.Code) assert.Equal(t, "AC X DB", signature) } @@ -159,7 +160,7 @@ func TestMiddlewareAbort(t *testing.T) { }) router.Use(func(c *Context) { signature += "C" - c.AbortWithStatus(401) + c.AbortWithStatus(http.StatusUnauthorized) c.Next() signature += "D" }) @@ -173,7 +174,7 @@ func TestMiddlewareAbort(t *testing.T) { w := performRequest(router, "GET", "/") // TEST - assert.Equal(t, 401, w.Code) + assert.Equal(t, http.StatusUnauthorized, w.Code) assert.Equal(t, "ACD", signature) } @@ -183,7 +184,7 @@ func TestMiddlewareAbortHandlersChainAndNext(t *testing.T) { router.Use(func(c *Context) { signature += "A" c.Next() - c.AbortWithStatus(410) + c.AbortWithStatus(http.StatusGone) signature += "B" }) @@ -195,7 +196,7 @@ func TestMiddlewareAbortHandlersChainAndNext(t *testing.T) { w := performRequest(router, "GET", "/") // TEST - assert.Equal(t, 410, w.Code) + assert.Equal(t, http.StatusGone, w.Code) assert.Equal(t, "ACB", signature) } @@ -207,7 +208,7 @@ func TestMiddlewareFailHandlersChain(t *testing.T) { router := New() router.Use(func(context *Context) { signature += "A" - context.AbortWithError(500, errors.New("foo")) + context.AbortWithError(http.StatusInternalServerError, errors.New("foo")) }) router.Use(func(context *Context) { signature += "B" @@ -218,25 +219,25 @@ func TestMiddlewareFailHandlersChain(t *testing.T) { w := performRequest(router, "GET", "/") // TEST - assert.Equal(t, 500, w.Code) + assert.Equal(t, http.StatusInternalServerError, w.Code) assert.Equal(t, "A", signature) } func TestMiddlewareWrite(t *testing.T) { router := New() router.Use(func(c *Context) { - c.String(400, "hola\n") + c.String(http.StatusBadRequest, "hola\n") }) router.Use(func(c *Context) { - c.XML(400, H{"foo": "bar"}) + c.XML(http.StatusBadRequest, H{"foo": "bar"}) }) router.Use(func(c *Context) { - c.JSON(400, H{"foo": "bar"}) + c.JSON(http.StatusBadRequest, H{"foo": "bar"}) }) router.GET("/", func(c *Context) { - c.JSON(400, H{"foo": "bar"}) + c.JSON(http.StatusBadRequest, H{"foo": "bar"}) }, func(c *Context) { - c.Render(400, sse.Event{ + c.Render(http.StatusBadRequest, sse.Event{ Event: "test", Data: "message", }) @@ -244,6 +245,6 @@ func TestMiddlewareWrite(t *testing.T) { w := performRequest(router, "GET", "/") - assert.Equal(t, 400, w.Code) + assert.Equal(t, http.StatusBadRequest, w.Code) assert.Equal(t, strings.Replace("hola\nbar{\"foo\":\"bar\"}{\"foo\":\"bar\"}event:test\ndata:message\n\n", " ", "", -1), strings.Replace(w.Body.String(), " ", "", -1)) } diff --git a/recovery_test.go b/recovery_test.go index fa065b13..53f4a071 100644 --- a/recovery_test.go +++ b/recovery_test.go @@ -6,6 +6,7 @@ package gin import ( "bytes" + "net/http" "testing" "github.com/stretchr/testify/assert" @@ -22,7 +23,7 @@ func TestPanicInHandler(t *testing.T) { // RUN w := performRequest(router, "GET", "/recovery") // TEST - assert.Equal(t, 500, w.Code) + assert.Equal(t, http.StatusInternalServerError, w.Code) assert.Contains(t, buffer.String(), "GET /recovery") assert.Contains(t, buffer.String(), "Oupps, Houston, we have a problem") assert.Contains(t, buffer.String(), "TestPanicInHandler") @@ -33,13 +34,13 @@ func TestPanicWithAbort(t *testing.T) { router := New() router.Use(RecoveryWithWriter(nil)) router.GET("/recovery", func(c *Context) { - c.AbortWithStatus(400) + c.AbortWithStatus(http.StatusBadRequest) panic("Oupps, Houston, we have a problem") }) // RUN w := performRequest(router, "GET", "/recovery") // TEST - assert.Equal(t, 400, w.Code) + assert.Equal(t, http.StatusBadRequest, w.Code) } func TestSource(t *testing.T) { diff --git a/render/redirect.go b/render/redirect.go index f874a351..a0634f5a 100644 --- a/render/redirect.go +++ b/render/redirect.go @@ -16,6 +16,8 @@ type Redirect struct { } func (r Redirect) Render(w http.ResponseWriter) error { + // todo(thinkerou): go1.6 not support StatusPermanentRedirect(308) + // when we upgrade go version we can use http.StatusPermanentRedirect if (r.Code < 300 || r.Code > 308) && r.Code != 201 { panic(fmt.Sprintf("Cannot redirect with status code %d", r.Code)) } diff --git a/render/render_test.go b/render/render_test.go index 8fad12b3..47abf262 100755 --- a/render/render_test.go +++ b/render/render_test.go @@ -286,7 +286,7 @@ func TestRenderRedirect(t *testing.T) { assert.NoError(t, err) data1 := Redirect{ - Code: 301, + Code: http.StatusMovedPermanently, Request: req, Location: "/new/location", } @@ -296,7 +296,7 @@ func TestRenderRedirect(t *testing.T) { assert.NoError(t, err) data2 := Redirect{ - Code: 200, + Code: http.StatusOK, Request: req, Location: "/new/location", } diff --git a/response_writer_test.go b/response_writer_test.go index fcc48b3b..cc5a89dc 100644 --- a/response_writer_test.go +++ b/response_writer_test.go @@ -35,10 +35,10 @@ func TestResponseWriterReset(t *testing.T) { writer.reset(testWritter) assert.Equal(t, -1, writer.size) - assert.Equal(t, 200, writer.status) + assert.Equal(t, http.StatusOK, writer.status) assert.Equal(t, testWritter, writer.ResponseWriter) assert.Equal(t, -1, w.Size()) - assert.Equal(t, 200, w.Status()) + assert.Equal(t, http.StatusOK, w.Status()) assert.False(t, w.Written()) } @@ -48,13 +48,13 @@ func TestResponseWriterWriteHeader(t *testing.T) { writer.reset(testWritter) w := ResponseWriter(writer) - w.WriteHeader(300) + w.WriteHeader(http.StatusMultipleChoices) assert.False(t, w.Written()) - assert.Equal(t, 300, w.Status()) - assert.NotEqual(t, 300, testWritter.Code) + assert.Equal(t, http.StatusMultipleChoices, w.Status()) + assert.NotEqual(t, http.StatusMultipleChoices, testWritter.Code) w.WriteHeader(-1) - assert.Equal(t, 300, w.Status()) + assert.Equal(t, http.StatusMultipleChoices, w.Status()) } func TestResponseWriterWriteHeadersNow(t *testing.T) { @@ -63,12 +63,12 @@ func TestResponseWriterWriteHeadersNow(t *testing.T) { writer.reset(testWritter) w := ResponseWriter(writer) - w.WriteHeader(300) + w.WriteHeader(http.StatusMultipleChoices) w.WriteHeaderNow() assert.True(t, w.Written()) assert.Equal(t, 0, w.Size()) - assert.Equal(t, 300, testWritter.Code) + assert.Equal(t, http.StatusMultipleChoices, testWritter.Code) writer.size = 10 w.WriteHeaderNow() @@ -84,8 +84,8 @@ func TestResponseWriterWrite(t *testing.T) { n, err := w.Write([]byte("hola")) assert.Equal(t, 4, n) assert.Equal(t, 4, w.Size()) - assert.Equal(t, 200, w.Status()) - assert.Equal(t, 200, testWritter.Code) + assert.Equal(t, http.StatusOK, w.Status()) + assert.Equal(t, http.StatusOK, testWritter.Code) assert.Equal(t, "hola", testWritter.Body.String()) assert.NoError(t, err) diff --git a/routergroup_test.go b/routergroup_test.go index a362e23d..ce3d54a2 100644 --- a/routergroup_test.go +++ b/routergroup_test.go @@ -5,6 +5,7 @@ package gin import ( + "net/http" "testing" "github.com/stretchr/testify/assert" @@ -50,7 +51,7 @@ func performRequestInGroup(t *testing.T, method string) { assert.Equal(t, "/v1/login/", login.BasePath()) handler := func(c *Context) { - c.String(400, "the method was %s and index %d", c.Request.Method, c.index) + c.String(http.StatusBadRequest, "the method was %s and index %d", c.Request.Method, c.index) } switch method { @@ -80,11 +81,11 @@ func performRequestInGroup(t *testing.T, method string) { } w := performRequest(router, method, "/v1/login/test") - assert.Equal(t, 400, w.Code) + assert.Equal(t, http.StatusBadRequest, w.Code) assert.Equal(t, "the method was "+method+" and index 3", w.Body.String()) w = performRequest(router, method, "/v1/test") - assert.Equal(t, 400, w.Code) + assert.Equal(t, http.StatusBadRequest, w.Code) assert.Equal(t, "the method was "+method+" and index 1", w.Body.String()) } diff --git a/routes_test.go b/routes_test.go index a2389f9b..23e749e2 100644 --- a/routes_test.go +++ b/routes_test.go @@ -80,20 +80,20 @@ func testRouteNotOK2(method string, t *testing.T) { func TestRouterMethod(t *testing.T) { router := New() router.PUT("/hey2", func(c *Context) { - c.String(200, "sup2") + c.String(http.StatusOK, "sup2") }) router.PUT("/hey", func(c *Context) { - c.String(200, "called") + c.String(http.StatusOK, "called") }) router.PUT("/hey3", func(c *Context) { - c.String(200, "sup3") + c.String(http.StatusOK, "sup3") }) w := performRequest(router, "PUT", "/hey") - assert.Equal(t, 200, w.Code) + assert.Equal(t, http.StatusOK, w.Code) assert.Equal(t, "called", w.Body.String()) } @@ -144,42 +144,42 @@ func TestRouteRedirectTrailingSlash(t *testing.T) { w := performRequest(router, "GET", "/path/") assert.Equal(t, "/path", w.Header().Get("Location")) - assert.Equal(t, 301, w.Code) + assert.Equal(t, http.StatusMovedPermanently, w.Code) w = performRequest(router, "GET", "/path2") assert.Equal(t, "/path2/", w.Header().Get("Location")) - assert.Equal(t, 301, w.Code) + assert.Equal(t, http.StatusMovedPermanently, w.Code) w = performRequest(router, "POST", "/path3/") assert.Equal(t, "/path3", w.Header().Get("Location")) - assert.Equal(t, 307, w.Code) + assert.Equal(t, http.StatusTemporaryRedirect, w.Code) w = performRequest(router, "PUT", "/path4") assert.Equal(t, "/path4/", w.Header().Get("Location")) - assert.Equal(t, 307, w.Code) + assert.Equal(t, http.StatusTemporaryRedirect, w.Code) w = performRequest(router, "GET", "/path") - assert.Equal(t, 200, w.Code) + assert.Equal(t, http.StatusOK, w.Code) w = performRequest(router, "GET", "/path2/") - assert.Equal(t, 200, w.Code) + assert.Equal(t, http.StatusOK, w.Code) w = performRequest(router, "POST", "/path3") - assert.Equal(t, 200, w.Code) + assert.Equal(t, http.StatusOK, w.Code) w = performRequest(router, "PUT", "/path4/") - assert.Equal(t, 200, w.Code) + assert.Equal(t, http.StatusOK, w.Code) router.RedirectTrailingSlash = false w = performRequest(router, "GET", "/path/") - assert.Equal(t, 404, w.Code) + assert.Equal(t, http.StatusNotFound, w.Code) w = performRequest(router, "GET", "/path2") - assert.Equal(t, 404, w.Code) + assert.Equal(t, http.StatusNotFound, w.Code) w = performRequest(router, "POST", "/path3/") - assert.Equal(t, 404, w.Code) + assert.Equal(t, http.StatusNotFound, w.Code) w = performRequest(router, "PUT", "/path4") - assert.Equal(t, 404, w.Code) + assert.Equal(t, http.StatusNotFound, w.Code) } func TestRouteRedirectFixedPath(t *testing.T) { @@ -194,19 +194,19 @@ func TestRouteRedirectFixedPath(t *testing.T) { w := performRequest(router, "GET", "/PATH") assert.Equal(t, "/path", w.Header().Get("Location")) - assert.Equal(t, 301, w.Code) + assert.Equal(t, http.StatusMovedPermanently, w.Code) w = performRequest(router, "GET", "/path2") assert.Equal(t, "/Path2", w.Header().Get("Location")) - assert.Equal(t, 301, w.Code) + assert.Equal(t, http.StatusMovedPermanently, w.Code) w = performRequest(router, "POST", "/path3") assert.Equal(t, "/PATH3", w.Header().Get("Location")) - assert.Equal(t, 307, w.Code) + assert.Equal(t, http.StatusTemporaryRedirect, w.Code) w = performRequest(router, "POST", "/path4") assert.Equal(t, "/Path4/", w.Header().Get("Location")) - assert.Equal(t, 307, w.Code) + assert.Equal(t, http.StatusTemporaryRedirect, w.Code) } // TestContextParamsGet tests that a parameter can be parsed from the URL. @@ -236,7 +236,7 @@ func TestRouteParamsByName(t *testing.T) { w := performRequest(router, "GET", "/test/john/smith/is/super/great") - assert.Equal(t, 200, w.Code) + assert.Equal(t, http.StatusOK, w.Code) assert.Equal(t, "john", name) assert.Equal(t, "smith", lastName) assert.Equal(t, "/is/super/great", wild) @@ -265,7 +265,7 @@ func TestRouteStaticFile(t *testing.T) { w2 := performRequest(router, "GET", "/result") assert.Equal(t, w, w2) - assert.Equal(t, 200, w.Code) + assert.Equal(t, http.StatusOK, w.Code) assert.Equal(t, "Gin Web Framework", w.Body.String()) assert.Equal(t, "text/plain; charset=utf-8", w.HeaderMap.Get("Content-Type")) @@ -273,7 +273,7 @@ func TestRouteStaticFile(t *testing.T) { w4 := performRequest(router, "HEAD", "/result") assert.Equal(t, w3, w4) - assert.Equal(t, 200, w3.Code) + assert.Equal(t, http.StatusOK, w3.Code) } // TestHandleStaticDir - ensure the root/sub dir handles properly @@ -283,7 +283,7 @@ func TestRouteStaticListingDir(t *testing.T) { w := performRequest(router, "GET", "/") - assert.Equal(t, 200, w.Code) + assert.Equal(t, http.StatusOK, w.Code) assert.Contains(t, w.Body.String(), "gin.go") assert.Equal(t, "text/html; charset=utf-8", w.HeaderMap.Get("Content-Type")) } @@ -295,7 +295,7 @@ func TestRouteStaticNoListing(t *testing.T) { w := performRequest(router, "GET", "/") - assert.Equal(t, 404, w.Code) + assert.Equal(t, http.StatusNotFound, w.Code) assert.NotContains(t, w.Body.String(), "gin.go") } @@ -310,7 +310,7 @@ func TestRouterMiddlewareAndStatic(t *testing.T) { w := performRequest(router, "GET", "/gin.go") - assert.Equal(t, 200, w.Code) + assert.Equal(t, http.StatusOK, w.Code) assert.Contains(t, w.Body.String(), "package gin") assert.Equal(t, "text/plain; charset=utf-8", w.HeaderMap.Get("Content-Type")) assert.NotEqual(t, w.HeaderMap.Get("Last-Modified"), "Mon, 02 Jan 2006 15:04:05 MST") @@ -348,14 +348,14 @@ func TestRouteNotAllowedDisabled(t *testing.T) { router.HandleMethodNotAllowed = false router.POST("/path", func(c *Context) {}) w := performRequest(router, "GET", "/path") - assert.Equal(t, 404, w.Code) + assert.Equal(t, http.StatusNotFound, w.Code) router.NoMethod(func(c *Context) { c.String(http.StatusTeapot, "responseText") }) w = performRequest(router, "GET", "/path") assert.Equal(t, "404 page not found", w.Body.String()) - assert.Equal(t, 404, w.Code) + assert.Equal(t, http.StatusNotFound, w.Code) } func TestRouterNotFound(t *testing.T) { @@ -370,20 +370,20 @@ func TestRouterNotFound(t *testing.T) { code int location string }{ - {"/path/", 301, "/path"}, // TSR -/ - {"/dir", 301, "/dir/"}, // TSR +/ - {"", 301, "/"}, // TSR +/ - {"/PATH", 301, "/path"}, // Fixed Case - {"/DIR/", 301, "/dir/"}, // Fixed Case - {"/PATH/", 301, "/path"}, // Fixed Case -/ - {"/DIR", 301, "/dir/"}, // Fixed Case +/ - {"/../path", 301, "/path"}, // CleanPath - {"/nope", 404, ""}, // NotFound + {"/path/", http.StatusMovedPermanently, "/path"}, // TSR -/ + {"/dir", http.StatusMovedPermanently, "/dir/"}, // TSR +/ + {"", http.StatusMovedPermanently, "/"}, // TSR +/ + {"/PATH", http.StatusMovedPermanently, "/path"}, // Fixed Case + {"/DIR/", http.StatusMovedPermanently, "/dir/"}, // Fixed Case + {"/PATH/", http.StatusMovedPermanently, "/path"}, // Fixed Case -/ + {"/DIR", http.StatusMovedPermanently, "/dir/"}, // Fixed Case +/ + {"/../path", http.StatusMovedPermanently, "/path"}, // CleanPath + {"/nope", http.StatusNotFound, ""}, // NotFound } for _, tr := range testRoutes { w := performRequest(router, "GET", tr.route) assert.Equal(t, tr.code, w.Code) - if w.Code != 404 { + if w.Code != http.StatusNotFound { assert.Equal(t, tr.location, fmt.Sprint(w.Header().Get("Location"))) } } @@ -391,24 +391,24 @@ func TestRouterNotFound(t *testing.T) { // Test custom not found handler var notFound bool router.NoRoute(func(c *Context) { - c.AbortWithStatus(404) + c.AbortWithStatus(http.StatusNotFound) notFound = true }) w := performRequest(router, "GET", "/nope") - assert.Equal(t, 404, w.Code) + assert.Equal(t, http.StatusNotFound, w.Code) assert.True(t, notFound) // Test other method than GET (want 307 instead of 301) router.PATCH("/path", func(c *Context) {}) w = performRequest(router, "PATCH", "/path/") - assert.Equal(t, 307, w.Code) + assert.Equal(t, http.StatusTemporaryRedirect, w.Code) assert.Equal(t, "map[Location:[/path]]", fmt.Sprint(w.Header())) // Test special case where no node for the prefix "/" exists router = New() router.GET("/a", func(c *Context) {}) w = performRequest(router, "GET", "/") - assert.Equal(t, 404, w.Code) + assert.Equal(t, http.StatusNotFound, w.Code) } func TestRouteRawPath(t *testing.T) { @@ -427,7 +427,7 @@ func TestRouteRawPath(t *testing.T) { }) w := performRequest(route, "POST", "/project/Some%2FOther%2FProject/build/222") - assert.Equal(t, 200, w.Code) + assert.Equal(t, http.StatusOK, w.Code) } func TestRouteRawPathNoUnescape(t *testing.T) { @@ -447,7 +447,7 @@ func TestRouteRawPathNoUnescape(t *testing.T) { }) w := performRequest(route, "POST", "/project/Some%2FOther%2FProject/build/333") - assert.Equal(t, 200, w.Code) + assert.Equal(t, http.StatusOK, w.Code) } func TestRouteServeErrorWithWriteHeader(t *testing.T) { diff --git a/utils_test.go b/utils_test.go index 95b5de5e..9b57c57b 100644 --- a/utils_test.go +++ b/utils_test.go @@ -25,7 +25,7 @@ type testStruct struct { func (t *testStruct) ServeHTTP(w http.ResponseWriter, req *http.Request) { assert.Equal(t.T, "POST", req.Method) assert.Equal(t.T, "/path", req.URL.Path) - w.WriteHeader(500) + w.WriteHeader(http.StatusInternalServerError) fmt.Fprint(w, "hello") } @@ -35,16 +35,16 @@ func TestWrap(t *testing.T) { router.GET("/path2", WrapF(func(w http.ResponseWriter, req *http.Request) { assert.Equal(t, "GET", req.Method) assert.Equal(t, "/path2", req.URL.Path) - w.WriteHeader(400) + w.WriteHeader(http.StatusBadRequest) fmt.Fprint(w, "hola!") })) w := performRequest(router, "POST", "/path") - assert.Equal(t, 500, w.Code) + assert.Equal(t, http.StatusInternalServerError, w.Code) assert.Equal(t, "hello", w.Body.String()) w = performRequest(router, "GET", "/path2") - assert.Equal(t, 400, w.Code) + assert.Equal(t, http.StatusBadRequest, w.Code) assert.Equal(t, "hola!", w.Body.String()) } From 6c8a9731345b6782c923054b0c973c2b4b9394a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=B0=E6=AC=A7?= Date: Tue, 14 Aug 2018 11:35:13 +0800 Subject: [PATCH 10/12] add issue and pull request template explain (#1483) * add issue/pr template explain * add issue/pr template explain --- .github/ISSUE_TEMPLATE.md | 13 +++++++++++++ .github/PULL_REQUEST_TEMPLATE.md | 7 +++++++ 2 files changed, 20 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 00000000..de067ce0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,13 @@ +- With issues: + - Use the search tool before opening a new issue. + - Please provide source code and commit sha if you found a bug. + - Review existing issues and provide feedback or react to them. + +- gin version (or commit ref): +- git version: +- operating system: + +## Description + +## Screenshots + diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..8630bc35 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,7 @@ +- With pull requests: + - Open your pull request against `master` + - Your pull request should have no more than two commits, if not you should squash them. + - It should pass all tests in the available continuous integrations systems such as TravisCI. + - You should add/modify tests to cover your proposed code changes. + - If your pull request contains a new feature, please document it on the README. + From b869fe1415e4b9eb52f247441830d502aece2d4d Mon Sep 17 00:00:00 2001 From: Javier Provecho Fernandez Date: Tue, 14 Aug 2018 10:58:52 +0200 Subject: [PATCH 11/12] docs: add changelog for v1.3.0, update authors and version const (#1478) * docs: add changelog for v1.3.0, update authors and version const * add link for every referenced pull request (#1481) * docs: add changelog for v1.3.0, update authors and version const * add link for pr --- AUTHORS.md | 6 +++++- CHANGELOG.md | 24 +++++++++++++++++++++++- gin.go | 2 +- 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/AUTHORS.md b/AUTHORS.md index 7ab7213d..dda19bcf 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -1,8 +1,12 @@ List of all the awesome people working to make Gin the best Web Framework in Go. +## gin 1.x series authors + +**Gin Core Team:** Bo-Yi Wu (@appleboy), 田欧 (@thinkerou), Javier Provecho (@javierprovecho) + ## gin 0.x series authors -**Maintainer:** Manu Martinez-Almeida (@manucorporat), Javier Provecho (@javierprovecho) +**Maintainers:** Manu Martinez-Almeida (@manucorporat), Javier Provecho (@javierprovecho) People and companies, who have contributed, in alphabetical order. diff --git a/CHANGELOG.md b/CHANGELOG.md index ee485ec3..e6a108ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,28 @@ # CHANGELOG -### Gin 1.2 +### Gin 1.3.0 + +- [NEW] Add [`func (*Context) QueryMap`](https://godoc.org/github.com/gin-gonic/gin#Context.QueryMap), [`func (*Context) GetQueryMap`](https://godoc.org/github.com/gin-gonic/gin#Context.GetQueryMap), [`func (*Context) PostFormMap`](https://godoc.org/github.com/gin-gonic/gin#Context.PostFormMap) and [`func (*Context) GetPostFormMap`](https://godoc.org/github.com/gin-gonic/gin#Context.GetPostFormMap) to support `type map[string]string` as query string or form parameters, see [#1383](https://github.com/gin-gonic/gin/pull/1383) +- [NEW] Add [`func (*Context) AsciiJSON`](https://godoc.org/github.com/gin-gonic/gin#Context.AsciiJSON), see [#1358](https://github.com/gin-gonic/gin/pull/1358) +- [NEW] Add `Pusher()` in [`type ResponseWriter`](https://godoc.org/github.com/gin-gonic/gin#ResponseWriter) for supporting http2 push, see [#1273](https://github.com/gin-gonic/gin/pull/1273) +- [NEW] Add [`func (*Context) DataFromReader`](https://godoc.org/github.com/gin-gonic/gin#Context.DataFromReader) for serving dynamic data, see [#1304](https://github.com/gin-gonic/gin/pull/1304) +- [NEW] Add [`func (*Context) ShouldBindBodyWith`](https://godoc.org/github.com/gin-gonic/gin#Context.ShouldBindBodyWith) allowing to call binding multiple times, see [#1341](https://github.com/gin-gonic/gin/pull/1341) +- [NEW] Support pointers in form binding, see [#1336](https://github.com/gin-gonic/gin/pull/1336) +- [NEW] Add [`func (*Context) JSONP`](https://godoc.org/github.com/gin-gonic/gin#Context.JSONP), see [#1333](https://github.com/gin-gonic/gin/pull/1333) +- [NEW] Support default value in form binding, see [#1138](https://github.com/gin-gonic/gin/pull/1138) +- [NEW] Expose validator engine in [`type StructValidator`](https://godoc.org/github.com/gin-gonic/gin/binding#StructValidator), see [#1277](https://github.com/gin-gonic/gin/pull/1277) +- [NEW] Add [`func (*Context) ShouldBind`](https://godoc.org/github.com/gin-gonic/gin#Context.ShouldBind), [`func (*Context) ShouldBindQuery`](https://godoc.org/github.com/gin-gonic/gin#Context.ShouldBindQuery) and [`func (*Context) ShouldBindJSON`](https://godoc.org/github.com/gin-gonic/gin#Context.ShouldBindJSON), see [#1047](https://github.com/gin-gonic/gin/pull/1047) +- [NEW] Add support for `time.Time` location in form binding, see [#1117](https://github.com/gin-gonic/gin/pull/1117) +- [NEW] Add [`func (*Context) BindQuery`](https://godoc.org/github.com/gin-gonic/gin#Context.BindQuery), see [#1029](https://github.com/gin-gonic/gin/pull/1029) +- [NEW] Make [jsonite](https://github.com/json-iterator/go) optional with build tags, see [#1026](https://github.com/gin-gonic/gin/pull/1026) +- [NEW] Show query string in logger, see [#999](https://github.com/gin-gonic/gin/pull/999) +- [NEW] Add [`func (*Context) SecureJSON`](https://godoc.org/github.com/gin-gonic/gin#Context.SecureJSON), see [#987](https://github.com/gin-gonic/gin/pull/987) and [#993](https://github.com/gin-gonic/gin/pull/993) +- [DEPRECATE] `func (*Context) GetCookie` for [`func (*Context) Cookie`](https://godoc.org/github.com/gin-gonic/gin#Context.Cookie) +- [FIX] Don't display color tags if [`func DisableConsoleColor`](https://godoc.org/github.com/gin-gonic/gin#DisableConsoleColor) called, see [#1072](https://github.com/gin-gonic/gin/pull/1072) +- [FIX] Gin Mode `""` when calling [`func Mode`](https://godoc.org/github.com/gin-gonic/gin#Mode) now returns `const DebugMode`, see [#1250](https://github.com/gin-gonic/gin/pull/1250) +- [FIX] `Flush()` now doesn't overwrite `responseWriter` status code, see [#1460](https://github.com/gin-gonic/gin/pull/1460) + +### Gin 1.2.0 - [NEW] Switch from godeps to govendor - [NEW] Add support for Let's Encrypt via gin-gonic/autotls diff --git a/gin.go b/gin.go index fc4d6564..aa62e014 100644 --- a/gin.go +++ b/gin.go @@ -16,7 +16,7 @@ import ( const ( // Version is Framework's version. - Version = "v1.2" + Version = "v1.3.0" defaultMultipartMemory = 32 << 20 // 32 MB ) From 64a45486421c37bd60af66ce96a3ef7b62a191aa Mon Sep 17 00:00:00 2001 From: Abner Chen Date: Wed, 15 Aug 2018 13:42:12 +0800 Subject: [PATCH 12/12] Fix typo in readme (#1490) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 28598baf..d8e3ffaa 100644 --- a/README.md +++ b/README.md @@ -679,7 +679,7 @@ $ curl "localhost:8085/bookable?check_in=2018-03-08&check_out=2018-03-09" {"error":"Key: 'Booking.CheckIn' Error:Field validation for 'CheckIn' failed on the 'bookabledate' tag"} ``` -[Struct level validations](https://github.com/go-playground/validator/releases/tag/v8.7) can also be registed this way. +[Struct level validations](https://github.com/go-playground/validator/releases/tag/v8.7) can also be registered this way. See the [struct-lvl-validation example](examples/struct-lvl-validations) to learn more. ### Only Bind Query String