Merge branch 'master' into master

This commit is contained in:
youngbloood 2018-08-15 14:00:07 +08:00 committed by GitHub
commit 67f7943237
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 401 additions and 280 deletions

13
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@ -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

7
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@ -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.

View File

@ -1,8 +1,12 @@
List of all the awesome people working to make Gin the best Web Framework in Go. 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 ## 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. People and companies, who have contributed, in alphabetical order.

View File

@ -1,6 +1,28 @@
# CHANGELOG # 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] Switch from godeps to govendor
- [NEW] Add support for Let's Encrypt via gin-gonic/autotls - [NEW] Add support for Let's Encrypt via gin-gonic/autotls

View File

@ -238,7 +238,7 @@ func main() {
func main() { func main() {
router := gin.Default() 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) { router.GET("/user/:name", func(c *gin.Context) {
name := c.Param("name") name := c.Param("name")
c.String(http.StatusOK, "Hello %s", name) c.String(http.StatusOK, "Hello %s", name)
@ -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"} {"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. See the [struct-lvl-validation example](examples/struct-lvl-validations) to learn more.
### Only Bind Query String ### Only Bind Query String
@ -1117,7 +1117,7 @@ func main() {
router.SetFuncMap(template.FuncMap{ router.SetFuncMap(template.FuncMap{
"formatAsDate": formatAsDate, "formatAsDate": formatAsDate,
}) })
router.LoadHTMLFiles("./fixtures/basic/raw.tmpl") router.LoadHTMLFiles("./testdata/template/raw.tmpl")
router.GET("/raw", func(c *gin.Context) { router.GET("/raw", func(c *gin.Context) {
c.HTML(http.StatusOK, "raw.tmpl", map[string]interface{}{ c.HTML(http.StatusOK, "raw.tmpl", map[string]interface{}{

View File

@ -93,7 +93,7 @@ func TestBasicAuthSucceed(t *testing.T) {
router := New() router := New()
router.Use(BasicAuth(accounts)) router.Use(BasicAuth(accounts))
router.GET("/login", func(c *Context) { router.GET("/login", func(c *Context) {
c.String(200, c.MustGet(AuthUserKey).(string)) c.String(http.StatusOK, c.MustGet(AuthUserKey).(string))
}) })
w := httptest.NewRecorder() w := httptest.NewRecorder()
@ -101,7 +101,7 @@ func TestBasicAuthSucceed(t *testing.T) {
req.Header.Set("Authorization", authorizationHeader("admin", "password")) req.Header.Set("Authorization", authorizationHeader("admin", "password"))
router.ServeHTTP(w, req) router.ServeHTTP(w, req)
assert.Equal(t, 200, w.Code) assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, "admin", w.Body.String()) assert.Equal(t, "admin", w.Body.String())
} }
@ -112,7 +112,7 @@ func TestBasicAuth401(t *testing.T) {
router.Use(BasicAuth(accounts)) router.Use(BasicAuth(accounts))
router.GET("/login", func(c *Context) { router.GET("/login", func(c *Context) {
called = true called = true
c.String(200, c.MustGet(AuthUserKey).(string)) c.String(http.StatusOK, c.MustGet(AuthUserKey).(string))
}) })
w := httptest.NewRecorder() w := httptest.NewRecorder()
@ -121,7 +121,7 @@ func TestBasicAuth401(t *testing.T) {
router.ServeHTTP(w, req) router.ServeHTTP(w, req)
assert.False(t, called) 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")) 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.Use(BasicAuthForRealm(accounts, "My Custom \"Realm\""))
router.GET("/login", func(c *Context) { router.GET("/login", func(c *Context) {
called = true called = true
c.String(200, c.MustGet(AuthUserKey).(string)) c.String(http.StatusOK, c.MustGet(AuthUserKey).(string))
}) })
w := httptest.NewRecorder() w := httptest.NewRecorder()
@ -141,6 +141,6 @@ func TestBasicAuth401WithCustomRealm(t *testing.T) {
router.ServeHTTP(w, req) router.ServeHTTP(w, req)
assert.False(t, called) 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")) assert.Equal(t, "Basic realm=\"My Custom \\\"Realm\\\"\"", w.HeaderMap.Get("WWW-Authenticate"))
} }

View File

@ -54,7 +54,7 @@ func BenchmarkOneRouteJSON(B *testing.B) {
Status string `json:"status"` Status string `json:"status"`
}{"ok"} }{"ok"}
router.GET("/json", func(c *Context) { router.GET("/json", func(c *Context) {
c.JSON(200, data) c.JSON(http.StatusOK, data)
}) })
runRequest(B, router, "GET", "/json") runRequest(B, router, "GET", "/json")
} }
@ -66,7 +66,7 @@ func BenchmarkOneRouteHTML(B *testing.B) {
router.SetHTMLTemplate(t) router.SetHTMLTemplate(t)
router.GET("/html", func(c *Context) { router.GET("/html", func(c *Context) {
c.HTML(200, "index", "hola") c.HTML(http.StatusOK, "index", "hola")
}) })
runRequest(B, router, "GET", "/html") runRequest(B, router, "GET", "/html")
} }
@ -82,7 +82,7 @@ func BenchmarkOneRouteSet(B *testing.B) {
func BenchmarkOneRouteString(B *testing.B) { func BenchmarkOneRouteString(B *testing.B) {
router := New() router := New()
router.GET("/text", func(c *Context) { 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") runRequest(B, router, "GET", "/text")
} }

View File

@ -5,7 +5,7 @@ import (
"io/ioutil" "io/ioutil"
"testing" "testing"
"github.com/gin-gonic/gin/binding/example" "github.com/gin-gonic/gin/testdata/protoexample"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/ugorji/go/codec" "github.com/ugorji/go/codec"
@ -55,12 +55,12 @@ func msgPackBody(t *testing.T) string {
} }
func TestBindingBodyProto(t *testing.T) { func TestBindingBodyProto(t *testing.T) {
test := example.Test{ test := protoexample.Test{
Label: proto.String("FOO"), Label: proto.String("FOO"),
} }
data, _ := proto.Marshal(&test) data, _ := proto.Marshal(&test)
req := requestWithBody("POST", "/", string(data)) req := requestWithBody("POST", "/", string(data))
form := example.Test{} form := protoexample.Test{}
body, _ := ioutil.ReadAll(req.Body) body, _ := ioutil.ReadAll(req.Body)
assert.NoError(t, ProtoBuf.BindBody(body, &form)) assert.NoError(t, ProtoBuf.BindBody(body, &form))
assert.Equal(t, test, form) assert.Equal(t, test, form)

View File

@ -14,7 +14,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/gin-gonic/gin/binding/example" "github.com/gin-gonic/gin/testdata/protoexample"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/ugorji/go/codec" "github.com/ugorji/go/codec"
@ -562,7 +562,7 @@ func TestBindingFormMultipartFail(t *testing.T) {
} }
func TestBindingProtoBuf(t *testing.T) { func TestBindingProtoBuf(t *testing.T) {
test := &example.Test{ test := &protoexample.Test{
Label: proto.String("yes"), Label: proto.String("yes"),
} }
data, _ := proto.Marshal(test) data, _ := proto.Marshal(test)
@ -574,7 +574,7 @@ func TestBindingProtoBuf(t *testing.T) {
} }
func TestBindingProtoBufFail(t *testing.T) { func TestBindingProtoBufFail(t *testing.T) {
test := &example.Test{ test := &protoexample.Test{
Label: proto.String("yes"), Label: proto.String("yes"),
} }
data, _ := proto.Marshal(test) 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) { func testProtoBodyBinding(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
assert.Equal(t, name, b.Name()) assert.Equal(t, name, b.Name())
obj := example.Test{} obj := protoexample.Test{}
req := requestWithBody("POST", path, body) req := requestWithBody("POST", path, body)
req.Header.Add("Content-Type", MIMEPROTOBUF) req.Header.Add("Content-Type", MIMEPROTOBUF)
err := b.Bind(req, &obj) err := b.Bind(req, &obj)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, "yes", *obj.Label) assert.Equal(t, "yes", *obj.Label)
obj = example.Test{} obj = protoexample.Test{}
req = requestWithBody("POST", badPath, badBody) req = requestWithBody("POST", badPath, badBody)
req.Header.Add("Content-Type", MIMEPROTOBUF) req.Header.Add("Content-Type", MIMEPROTOBUF)
err = ProtoBuf.Bind(req, &obj) 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) { func testProtoBodyBindingFail(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
assert.Equal(t, name, b.Name()) assert.Equal(t, name, b.Name())
obj := example.Test{} obj := protoexample.Test{}
req := requestWithBody("POST", path, body) req := requestWithBody("POST", path, body)
req.Body = ioutil.NopCloser(&hook{}) 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) err := b.Bind(req, &obj)
assert.Error(t, err) assert.Error(t, err)
obj = example.Test{} obj = protoexample.Test{}
req = requestWithBody("POST", badPath, badBody) req = requestWithBody("POST", badPath, badBody)
req.Header.Add("Content-Type", MIMEPROTOBUF) req.Header.Add("Content-Type", MIMEPROTOBUF)
err = ProtoBuf.Bind(req, &obj) err = ProtoBuf.Bind(req, &obj)

View File

@ -9,6 +9,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"html/template" "html/template"
"io"
"mime/multipart" "mime/multipart"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
@ -21,7 +22,6 @@ import (
"github.com/gin-gonic/gin/binding" "github.com/gin-gonic/gin/binding"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"golang.org/x/net/context" "golang.org/x/net/context"
"io"
) )
var _ context.Context = &Context{} var _ context.Context = &Context{}
@ -585,10 +585,11 @@ func TestContextGetCookie(t *testing.T) {
} }
func TestContextBodyAllowedForStatus(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(102))
assert.False(t, false, bodyAllowedForStatus(204)) assert.False(t, false, bodyAllowedForStatus(http.StatusNoContent))
assert.False(t, false, bodyAllowedForStatus(304)) assert.False(t, false, bodyAllowedForStatus(http.StatusNotModified))
assert.True(t, true, bodyAllowedForStatus(500)) assert.True(t, true, bodyAllowedForStatus(http.StatusInternalServerError))
} }
type TestPanicRender struct { type TestPanicRender struct {
@ -619,9 +620,9 @@ func TestContextRenderJSON(t *testing.T) {
w := httptest.NewRecorder() w := httptest.NewRecorder()
c, _ := CreateTestContext(w) 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, "{\"foo\":\"bar\"}", w.Body.String())
assert.Equal(t, "application/json; charset=utf-8", w.HeaderMap.Get("Content-Type")) 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, _ := CreateTestContext(w)
c.Request, _ = http.NewRequest("GET", "http://example.com/?callback=x", nil) 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, "x({\"foo\":\"bar\"})", w.Body.String())
assert.Equal(t, "application/javascript; charset=utf-8", w.HeaderMap.Get("Content-Type")) 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, _ := CreateTestContext(w)
c.Request, _ = http.NewRequest("GET", "http://example.com", nil) 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, "{\"foo\":\"bar\"}", w.Body.String())
assert.Equal(t, "application/json; charset=utf-8", w.HeaderMap.Get("Content-Type")) 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() w := httptest.NewRecorder()
c, _ := CreateTestContext(w) 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.Empty(t, w.Body.String())
assert.Equal(t, "application/json; charset=utf-8", w.HeaderMap.Get("Content-Type")) 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, _ := CreateTestContext(w)
c.Header("Content-Type", "application/vnd.api+json") 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, "{\"foo\":\"bar\"}", w.Body.String())
assert.Equal(t, "application/vnd.api+json", w.HeaderMap.Get("Content-Type")) 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, _ := CreateTestContext(w)
c.Header("Content-Type", "application/vnd.api+json") 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.Empty(t, w.Body.String())
assert.Equal(t, w.HeaderMap.Get("Content-Type"), "application/vnd.api+json") assert.Equal(t, w.HeaderMap.Get("Content-Type"), "application/vnd.api+json")
} }
@ -699,9 +700,9 @@ func TestContextRenderIndentedJSON(t *testing.T) {
w := httptest.NewRecorder() w := httptest.NewRecorder()
c, _ := CreateTestContext(w) 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, "{\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")) 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() w := httptest.NewRecorder()
c, _ := CreateTestContext(w) 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.Empty(t, w.Body.String())
assert.Equal(t, "application/json; charset=utf-8", w.HeaderMap.Get("Content-Type")) 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) c, router := CreateTestContext(w)
router.SecureJsonPrefix("&&&START&&&") 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, "&&&START&&&[\"foo\",\"bar\"]", w.Body.String())
assert.Equal(t, "application/json; charset=utf-8", w.HeaderMap.Get("Content-Type")) 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() w := httptest.NewRecorder()
c, _ := CreateTestContext(w) 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.Empty(t, w.Body.String())
assert.Equal(t, "application/json; charset=utf-8", w.HeaderMap.Get("Content-Type")) 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}}`)) templ := template.Must(template.New("t").Parse(`Hello {{.name}}`))
router.SetHTMLTemplate(templ) 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, "Hello alexandernyquist", w.Body.String())
assert.Equal(t, "text/html; charset=utf-8", w.HeaderMap.Get("Content-Type")) 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()) 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, "Hello alexandernyquist", w.Body.String())
assert.Equal(t, "text/html; charset=utf-8", w.HeaderMap.Get("Content-Type")) 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}}`)) templ := template.Must(template.New("t").Parse(`Hello {{.name}}`))
router.SetHTMLTemplate(templ) 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.Empty(t, w.Body.String())
assert.Equal(t, "text/html; charset=utf-8", w.HeaderMap.Get("Content-Type")) 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() w := httptest.NewRecorder()
c, _ := CreateTestContext(w) 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, "<map><foo>bar</foo></map>", w.Body.String()) assert.Equal(t, "<map><foo>bar</foo></map>", w.Body.String())
assert.Equal(t, "application/xml; charset=utf-8", w.HeaderMap.Get("Content-Type")) 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() w := httptest.NewRecorder()
c, _ := CreateTestContext(w) 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.Empty(t, w.Body.String())
assert.Equal(t, "application/xml; charset=utf-8", w.HeaderMap.Get("Content-Type")) 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() w := httptest.NewRecorder()
c, _ := CreateTestContext(w) 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, "test string 2", w.Body.String())
assert.Equal(t, "text/plain; charset=utf-8", w.HeaderMap.Get("Content-Type")) 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() w := httptest.NewRecorder()
c, _ := CreateTestContext(w) 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.Empty(t, w.Body.String())
assert.Equal(t, "text/plain; charset=utf-8", w.HeaderMap.Get("Content-Type")) 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, _ := CreateTestContext(w)
c.Header("Content-Type", "text/html; charset=utf-8") c.Header("Content-Type", "text/html; charset=utf-8")
c.String(201, "<html>%s %d</html>", "string", 3) c.String(http.StatusCreated, "<html>%s %d</html>", "string", 3)
assert.Equal(t, 201, w.Code) assert.Equal(t, http.StatusCreated, w.Code)
assert.Equal(t, "<html>string 3</html>", w.Body.String()) assert.Equal(t, "<html>string 3</html>", w.Body.String())
assert.Equal(t, "text/html; charset=utf-8", w.HeaderMap.Get("Content-Type")) 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, _ := CreateTestContext(w)
c.Header("Content-Type", "text/html; charset=utf-8") c.Header("Content-Type", "text/html; charset=utf-8")
c.String(204, "<html>%s %d</html>", "string", 3) c.String(http.StatusNoContent, "<html>%s %d</html>", "string", 3)
assert.Equal(t, 204, w.Code) assert.Equal(t, http.StatusNoContent, w.Code)
assert.Empty(t, w.Body.String()) assert.Empty(t, w.Body.String())
assert.Equal(t, "text/html; charset=utf-8", w.HeaderMap.Get("Content-Type")) 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() w := httptest.NewRecorder()
c, _ := CreateTestContext(w) 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, "foo,bar", w.Body.String())
assert.Equal(t, "text/csv", w.HeaderMap.Get("Content-Type")) assert.Equal(t, "text/csv", w.HeaderMap.Get("Content-Type"))
} }
@ -904,9 +905,9 @@ func TestContextRenderNoContentData(t *testing.T) {
w := httptest.NewRecorder() w := httptest.NewRecorder()
c, _ := CreateTestContext(w) 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.Empty(t, w.Body.String())
assert.Equal(t, "text/csv", w.HeaderMap.Get("Content-Type")) 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.Request, _ = http.NewRequest("GET", "/", nil)
c.File("./gin.go") 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.Contains(t, w.Body.String(), "func New() *Engine {")
assert.Equal(t, "text/plain; charset=utf-8", w.HeaderMap.Get("Content-Type")) 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() w := httptest.NewRecorder()
c, _ := CreateTestContext(w) 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, "foo: bar\n", w.Body.String())
assert.Equal(t, "application/x-yaml; charset=utf-8", w.HeaderMap.Get("Content-Type")) 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(299, "/new_path") })
assert.Panics(t, func() { c.Redirect(309, "/new_path") }) assert.Panics(t, func() { c.Redirect(309, "/new_path") })
c.Redirect(301, "/path") c.Redirect(http.StatusMovedPermanently, "/path")
c.Writer.WriteHeaderNow() c.Writer.WriteHeaderNow()
assert.Equal(t, 301, w.Code) assert.Equal(t, http.StatusMovedPermanently, w.Code)
assert.Equal(t, "/path", w.Header().Get("Location")) assert.Equal(t, "/path", w.Header().Get("Location"))
} }
@ -989,10 +990,10 @@ func TestContextRenderRedirectWithAbsolutePath(t *testing.T) {
c, _ := CreateTestContext(w) c, _ := CreateTestContext(w)
c.Request, _ = http.NewRequest("POST", "http://example.com", nil) 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() 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")) assert.Equal(t, "http://google.com", w.Header().Get("Location"))
} }
@ -1001,21 +1002,23 @@ func TestContextRenderRedirectWith201(t *testing.T) {
c, _ := CreateTestContext(w) c, _ := CreateTestContext(w)
c.Request, _ = http.NewRequest("POST", "http://example.com", nil) c.Request, _ = http.NewRequest("POST", "http://example.com", nil)
c.Redirect(201, "/resource") c.Redirect(http.StatusCreated, "/resource")
c.Writer.WriteHeaderNow() c.Writer.WriteHeaderNow()
assert.Equal(t, 201, w.Code) assert.Equal(t, http.StatusCreated, w.Code)
assert.Equal(t, "/resource", w.Header().Get("Location")) assert.Equal(t, "/resource", w.Header().Get("Location"))
} }
func TestContextRenderRedirectAll(t *testing.T) { func TestContextRenderRedirectAll(t *testing.T) {
c, _ := CreateTestContext(httptest.NewRecorder()) c, _ := CreateTestContext(httptest.NewRecorder())
c.Request, _ = http.NewRequest("POST", "http://example.com", nil) c.Request, _ = http.NewRequest("POST", "http://example.com", nil)
assert.Panics(t, func() { c.Redirect(200, "/resource") }) assert.Panics(t, func() { c.Redirect(http.StatusOK, "/resource") })
assert.Panics(t, func() { c.Redirect(202, "/resource") }) assert.Panics(t, func() { c.Redirect(http.StatusAccepted, "/resource") })
assert.Panics(t, func() { c.Redirect(299, "/resource") }) assert.Panics(t, func() { c.Redirect(299, "/resource") })
assert.Panics(t, func() { c.Redirect(309, "/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") }) assert.NotPanics(t, func() { c.Redirect(308, "/resource") })
} }
@ -1024,12 +1027,12 @@ func TestContextNegotiationWithJSON(t *testing.T) {
c, _ := CreateTestContext(w) c, _ := CreateTestContext(w)
c.Request, _ = http.NewRequest("POST", "", nil) c.Request, _ = http.NewRequest("POST", "", nil)
c.Negotiate(200, Negotiate{ c.Negotiate(http.StatusOK, Negotiate{
Offered: []string{MIMEJSON, MIMEXML}, Offered: []string{MIMEJSON, MIMEXML},
Data: H{"foo": "bar"}, 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, "{\"foo\":\"bar\"}", w.Body.String())
assert.Equal(t, "application/json; charset=utf-8", w.HeaderMap.Get("Content-Type")) 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, _ := CreateTestContext(w)
c.Request, _ = http.NewRequest("POST", "", nil) c.Request, _ = http.NewRequest("POST", "", nil)
c.Negotiate(200, Negotiate{ c.Negotiate(http.StatusOK, Negotiate{
Offered: []string{MIMEXML, MIMEJSON}, Offered: []string{MIMEXML, MIMEJSON},
Data: H{"foo": "bar"}, Data: H{"foo": "bar"},
}) })
assert.Equal(t, 200, w.Code) assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, "<map><foo>bar</foo></map>", w.Body.String()) assert.Equal(t, "<map><foo>bar</foo></map>", w.Body.String())
assert.Equal(t, "application/xml; charset=utf-8", w.HeaderMap.Get("Content-Type")) 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}}`)) templ := template.Must(template.New("t").Parse(`Hello {{.name}}`))
router.SetHTMLTemplate(templ) router.SetHTMLTemplate(templ)
c.Negotiate(200, Negotiate{ c.Negotiate(http.StatusOK, Negotiate{
Offered: []string{MIMEHTML}, Offered: []string{MIMEHTML},
Data: H{"name": "gin"}, Data: H{"name": "gin"},
HTMLName: "t", 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, "Hello gin", w.Body.String())
assert.Equal(t, "text/html; charset=utf-8", w.HeaderMap.Get("Content-Type")) 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, _ := CreateTestContext(w)
c.Request, _ = http.NewRequest("POST", "", nil) c.Request, _ = http.NewRequest("POST", "", nil)
c.Negotiate(200, Negotiate{ c.Negotiate(http.StatusOK, Negotiate{
Offered: []string{MIMEPOSTForm}, Offered: []string{MIMEPOSTForm},
}) })
assert.Equal(t, 406, w.Code) assert.Equal(t, http.StatusNotAcceptable, w.Code)
assert.Equal(t, c.index, abortIndex) assert.Equal(t, c.index, abortIndex)
assert.True(t, c.IsAborted()) assert.True(t, c.IsAborted())
} }
@ -1134,11 +1137,11 @@ func TestContextAbortWithStatus(t *testing.T) {
c, _ := CreateTestContext(w) c, _ := CreateTestContext(w)
c.index = 4 c.index = 4
c.AbortWithStatus(401) c.AbortWithStatus(http.StatusUnauthorized)
assert.Equal(t, abortIndex, c.index) assert.Equal(t, abortIndex, c.index)
assert.Equal(t, 401, c.Writer.Status()) assert.Equal(t, http.StatusUnauthorized, c.Writer.Status())
assert.Equal(t, 401, w.Code) assert.Equal(t, http.StatusUnauthorized, w.Code)
assert.True(t, c.IsAborted()) assert.True(t, c.IsAborted())
} }
@ -1156,11 +1159,11 @@ func TestContextAbortWithStatusJSON(t *testing.T) {
in.Bar = "barValue" in.Bar = "barValue"
in.Foo = "fooValue" in.Foo = "fooValue"
c.AbortWithStatusJSON(415, in) c.AbortWithStatusJSON(http.StatusUnsupportedMediaType, in)
assert.Equal(t, abortIndex, c.index) assert.Equal(t, abortIndex, c.index)
assert.Equal(t, 415, c.Writer.Status()) assert.Equal(t, http.StatusUnsupportedMediaType, c.Writer.Status())
assert.Equal(t, 415, w.Code) assert.Equal(t, http.StatusUnsupportedMediaType, w.Code)
assert.True(t, c.IsAborted()) assert.True(t, c.IsAborted())
contentType := w.Header().Get("Content-Type") contentType := w.Header().Get("Content-Type")
@ -1223,9 +1226,9 @@ func TestContextAbortWithError(t *testing.T) {
w := httptest.NewRecorder() w := httptest.NewRecorder()
c, _ := CreateTestContext(w) 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.Equal(t, abortIndex, c.index)
assert.True(t, c.IsAborted()) assert.True(t, c.IsAborted())
} }
@ -1333,7 +1336,7 @@ func TestContextBadAutoBind(t *testing.T) {
assert.Empty(t, obj.Bar) assert.Empty(t, obj.Bar)
assert.Empty(t, obj.Foo) assert.Empty(t, obj.Foo)
assert.Equal(t, 400, w.Code) assert.Equal(t, http.StatusBadRequest, w.Code)
assert.True(t, c.IsAborted()) assert.True(t, c.IsAborted())
} }
@ -1560,6 +1563,26 @@ func TestContextRenderDataFromReader(t *testing.T) {
assert.Equal(t, extraHeaders["Content-Disposition"], w.HeaderMap.Get("Content-Disposition")) 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) { func TestContextStream(t *testing.T) {
w := CreateTestResponseRecorder() w := CreateTestResponseRecorder()
c, _ := CreateTestContext(w) c, _ := CreateTestContext(w)

View File

@ -72,7 +72,7 @@ func TestDebugPrintLoadTemplate(t *testing.T) {
setup(&w) setup(&w)
defer teardown() 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) debugPrintLoadTemplate(templ)
assert.Regexp(t, `^\[GIN-debug\] Loaded HTML Templates \(2\): \n(\t- \n|\t- hello\.tmpl\n){2}\n`, w.String()) assert.Regexp(t, `^\[GIN-debug\] Loaded HTML Templates \(2\): \n(\t- \n|\t- hello\.tmpl\n){2}\n`, w.String())
} }

View File

@ -1,6 +1,8 @@
package main package main
import ( import (
"net/http"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
@ -13,7 +15,7 @@ func setupRouter() *gin.Engine {
// Ping test // Ping test
r.GET("/ping", func(c *gin.Context) { r.GET("/ping", func(c *gin.Context) {
c.String(200, "pong") c.String(http.StatusOK, "pong")
}) })
// Get user value // Get user value
@ -21,9 +23,9 @@ func setupRouter() *gin.Engine {
user := c.Params.ByName("name") user := c.Params.ByName("name")
value, ok := DB[user] value, ok := DB[user]
if ok { if ok {
c.JSON(200, gin.H{"user": user, "value": value}) c.JSON(http.StatusOK, gin.H{"user": user, "value": value})
} else { } 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 { if c.Bind(&json) == nil {
DB[user] = json.Value DB[user] = json.Value
c.JSON(200, gin.H{"status": "ok"}) c.JSON(http.StatusOK, gin.H{"status": "ok"})
} }
}) })

View File

@ -15,6 +15,6 @@ func TestPingRoute(t *testing.T) {
req, _ := http.NewRequest("GET", "/ping", nil) req, _ := http.NewRequest("GET", "/ping", nil)
router.ServeHTTP(w, req) router.ServeHTTP(w, req)
assert.Equal(t, 200, w.Code) assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, "pong", w.Body.String()) assert.Equal(t, "pong", w.Body.String())
} }

View File

@ -1,6 +1,8 @@
package main package main
import ( import (
"net/http"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/thinkerou/favicon" "github.com/thinkerou/favicon"
) )
@ -9,7 +11,7 @@ func main() {
app := gin.Default() app := gin.Default()
app.Use(favicon.New("./favicon.ico")) app.Use(favicon.New("./favicon.ico"))
app.GET("/ping", func(c *gin.Context) { app.GET("/ping", func(c *gin.Context) {
c.String(200, "Hello favicon.") c.String(http.StatusOK, "Hello favicon.")
}) })
app.Run(":8080") app.Run(":8080")
} }

View File

@ -3,6 +3,7 @@ package main
import ( import (
"html/template" "html/template"
"log" "log"
"net/http"
"os" "os"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
@ -27,7 +28,7 @@ func main() {
r.SetHTMLTemplate(html) r.SetHTMLTemplate(html)
r.GET("/welcome", func(c *gin.Context) { r.GET("/welcome", func(c *gin.Context) {
c.HTML(200, "https", gin.H{ c.HTML(http.StatusOK, "https", gin.H{
"status": "success", "status": "success",
}) })
}) })

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"html" "html"
"io" "io"
"net/http"
"strings" "strings"
"time" "time"
@ -21,12 +22,12 @@ func rateLimit(c *gin.Context) {
fmt.Println("ip blocked") fmt.Println("ip blocked")
} }
c.Abort() c.Abort()
c.String(503, "you were automatically banned :)") c.String(http.StatusServiceUnavailable, "you were automatically banned :)")
} }
} }
func index(c *gin.Context) { func index(c *gin.Context) {
c.Redirect(301, "/room/hn") c.Redirect(http.StatusMovedPermanently, "/room/hn")
} }
func roomGET(c *gin.Context) { func roomGET(c *gin.Context) {
@ -38,7 +39,7 @@ func roomGET(c *gin.Context) {
if len(nick) > 13 { if len(nick) > 13 {
nick = nick[0:12] + "..." 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, "roomid": roomid,
"nick": nick, "nick": nick,
"timestamp": time.Now().Unix(), "timestamp": time.Now().Unix(),
@ -55,7 +56,7 @@ func roomPOST(c *gin.Context) {
validMessage := len(message) > 1 && len(message) < 200 validMessage := len(message) > 1 && len(message) < 200
validNick := len(nick) > 1 && len(nick) < 14 validNick := len(nick) > 1 && len(nick) < 14
if !validMessage || !validNick { if !validMessage || !validNick {
c.JSON(400, gin.H{ c.JSON(http.StatusBadRequest, gin.H{
"status": "failed", "status": "failed",
"error": "the message or nickname is too long", "error": "the message or nickname is too long",
}) })
@ -68,7 +69,7 @@ func roomPOST(c *gin.Context) {
} }
messages.Add("inbound", 1) messages.Add("inbound", 1)
room(roomid).Submit(post) room(roomid).Submit(post)
c.JSON(200, post) c.JSON(http.StatusOK, post)
} }
func streamRoom(c *gin.Context) { func streamRoom(c *gin.Context) {

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"io" "io"
"math/rand" "math/rand"
"net/http"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
@ -34,7 +35,7 @@ func stream(c *gin.Context) {
func roomGET(c *gin.Context) { func roomGET(c *gin.Context) {
roomid := c.Param("roomid") roomid := c.Param("roomid")
userid := fmt.Sprint(rand.Int31()) userid := fmt.Sprint(rand.Int31())
c.HTML(200, "chat_room", gin.H{ c.HTML(http.StatusOK, "chat_room", gin.H{
"roomid": roomid, "roomid": roomid,
"userid": userid, "userid": userid,
}) })
@ -46,7 +47,7 @@ func roomPOST(c *gin.Context) {
message := c.PostForm("message") message := c.PostForm("message")
room(roomid).Submit(userid + ": " + message) room(roomid).Submit(userid + ": " + message)
c.JSON(200, gin.H{ c.JSON(http.StatusOK, gin.H{
"status": "success", "status": "success",
"message": message, "message": message,
}) })

View File

@ -20,7 +20,7 @@ func main() {
router.SetFuncMap(template.FuncMap{ router.SetFuncMap(template.FuncMap{
"formatAsDate": formatAsDate, "formatAsDate": formatAsDate,
}) })
router.LoadHTMLFiles("../../fixtures/basic/raw.tmpl") router.LoadHTMLFiles("../../testdata/template/raw.tmpl")
router.GET("/raw", func(c *gin.Context) { router.GET("/raw", func(c *gin.Context) {
c.HTML(http.StatusOK, "raw.tmpl", map[string]interface{}{ c.HTML(http.StatusOK, "raw.tmpl", map[string]interface{}{

27
gin.go
View File

@ -16,7 +16,7 @@ import (
const ( const (
// Version is Framework's version. // Version is Framework's version.
Version = "v1.2" Version = "v1.3.0"
defaultMultipartMemory = 32 << 20 // 32 MB defaultMultipartMemory = 32 << 20 // 32 MB
) )
@ -349,7 +349,9 @@ func (engine *Engine) handleHTTPRequest(c *Context) {
// Find root of the tree for the given HTTP method // Find root of the tree for the given HTTP method
t := engine.trees t := engine.trees
for i, tl := 0, len(t); i < tl; i++ { for i, tl := 0, len(t); i < tl; i++ {
if t[i].method == httpMethod { if t[i].method != httpMethod {
continue
}
root := t[i].root root := t[i].root
// Find route in tree // Find route in tree
handlers, params, relativePath, tsr := root.getValue(path, c.Params, unescape) handlers, params, relativePath, tsr := root.getValue(path, c.Params, unescape)
@ -372,19 +374,19 @@ func (engine *Engine) handleHTTPRequest(c *Context) {
} }
break break
} }
}
if engine.HandleMethodNotAllowed { if engine.HandleMethodNotAllowed {
for _, tree := range engine.trees { for _, tree := range engine.trees {
if tree.method != httpMethod { if tree.method == httpMethod {
if handlers, _, _, _ := tree.root.getValue(path, nil, unescape); handlers != nil { continue
}
if handlers, _, _ := tree.root.getValue(path, nil, unescape); handlers != nil {
c.handlers = engine.allNoMethod c.handlers = engine.allNoMethod
serveError(c, http.StatusMethodNotAllowed, default405Body) serveError(c, http.StatusMethodNotAllowed, default405Body)
return return
} }
} }
} }
}
c.handlers = engine.allNoRoute c.handlers = engine.allNoRoute
serveError(c, http.StatusNotFound, default404Body) serveError(c, http.StatusNotFound, default404Body)
} }
@ -394,14 +396,16 @@ var mimePlain = []string{MIMEPlain}
func serveError(c *Context, code int, defaultMessage []byte) { func serveError(c *Context, code int, defaultMessage []byte) {
c.writermem.status = code c.writermem.status = code
c.Next() c.Next()
if !c.writermem.Written() { if c.writermem.Written() {
return
}
if c.writermem.Status() == code { if c.writermem.Status() == code {
c.writermem.Header()["Content-Type"] = mimePlain c.writermem.Header()["Content-Type"] = mimePlain
c.Writer.Write(defaultMessage) c.Writer.Write(defaultMessage)
} else { return
}
c.writermem.WriteHeaderNow() c.writermem.WriteHeaderNow()
} return
}
} }
func redirectTrailingSlash(c *Context) { func redirectTrailingSlash(c *Context) {
@ -412,10 +416,9 @@ func redirectTrailingSlash(c *Context) {
code = http.StatusTemporaryRedirect code = http.StatusTemporaryRedirect
} }
req.URL.Path = path + "/"
if length := len(path); length > 1 && path[length-1] == '/' { if length := len(path); length > 1 && path[length-1] == '/' {
req.URL.Path = 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()) debugPrint("redirecting request %d: %s --> %s", code, path, req.URL.String())
http.Redirect(c.Writer, req, req.URL.String(), code) http.Redirect(c.Writer, req, req.URL.String(), code)

View File

@ -30,7 +30,7 @@ func setupHTMLFiles(t *testing.T, mode string, tls bool) func() {
router.SetFuncMap(template.FuncMap{ router.SetFuncMap(template.FuncMap{
"formatAsDate": formatAsDate, "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) { router.GET("/test", func(c *Context) {
c.HTML(http.StatusOK, "hello.tmpl", map[string]string{"name": "world"}) 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 { if tls {
// these files generated by `go run $GOROOT/src/crypto/tls/generate_cert.go --host 127.0.0.1` // 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 { } else {
router.Run(":8888") router.Run(":8888")
} }
@ -59,7 +59,7 @@ func setupHTMLGlob(t *testing.T, mode string, tls bool) func() {
router.SetFuncMap(template.FuncMap{ router.SetFuncMap(template.FuncMap{
"formatAsDate": formatAsDate, "formatAsDate": formatAsDate,
}) })
router.LoadHTMLGlob("./fixtures/basic/*") router.LoadHTMLGlob("./testdata/template/*")
router.GET("/test", func(c *Context) { router.GET("/test", func(c *Context) {
c.HTML(http.StatusOK, "hello.tmpl", map[string]string{"name": "world"}) 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 { if tls {
// these files generated by `go run $GOROOT/src/crypto/tls/generate_cert.go --host 127.0.0.1` // 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 { } else {
router.Run(":8888") router.Run(":8888")
} }

View File

@ -293,7 +293,7 @@ func githubConfigRouter(router *Engine) {
for _, param := range c.Params { for _, param := range c.Params {
output[param.Key] = param.Value output[param.Key] = param.Value
} }
c.JSON(200, output) c.JSON(http.StatusOK, output)
}) })
} }
} }

View File

@ -7,6 +7,7 @@ package gin
import ( import (
"fmt" "fmt"
"io" "io"
"net/http"
"os" "os"
"time" "time"
@ -118,11 +119,11 @@ func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc {
func colorForStatus(code int) string { func colorForStatus(code int) string {
switch { switch {
case code >= 200 && code < 300: case code >= http.StatusOK && code < http.StatusMultipleChoices:
return green return green
case code >= 300 && code < 400: case code >= http.StatusMultipleChoices && code < http.StatusBadRequest:
return white return white
case code >= 400 && code < 500: case code >= http.StatusBadRequest && code < http.StatusInternalServerError:
return yellow return yellow
default: default:
return red return red

View File

@ -7,6 +7,7 @@ package gin
import ( import (
"bytes" "bytes"
"errors" "errors"
"net/http"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -93,9 +94,9 @@ func TestColorForMethod(t *testing.T) {
} }
func TestColorForStatus(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, 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(301), "3xx should be white") 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(404), "4xx should be yellow") 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") 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")) c.Error(errors.New("this is an error"))
}) })
router.GET("/abort", func(c *Context) { 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) { router.GET("/print", func(c *Context) {
c.Error(errors.New("this is an error")) c.Error(errors.New("this is an error"))
c.String(500, "hola!") c.String(http.StatusInternalServerError, "hola!")
}) })
w := performRequest(router, "GET", "/error") 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()) assert.Equal(t, "{\"error\":\"this is an error\"}", w.Body.String())
w = performRequest(router, "GET", "/abort") 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()) assert.Equal(t, "{\"error\":\"no authorized\"}", w.Body.String())
w = performRequest(router, "GET", "/print") 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()) assert.Equal(t, "hola!{\"error\":\"this is an error\"}", w.Body.String())
} }

View File

@ -6,6 +6,7 @@ package gin
import ( import (
"errors" "errors"
"net/http"
"strings" "strings"
"testing" "testing"
@ -37,7 +38,7 @@ func TestMiddlewareGeneralCase(t *testing.T) {
w := performRequest(router, "GET", "/") w := performRequest(router, "GET", "/")
// TEST // TEST
assert.Equal(t, 200, w.Code) assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, "ACDB", signature) assert.Equal(t, "ACDB", signature)
} }
@ -73,7 +74,7 @@ func TestMiddlewareNoRoute(t *testing.T) {
w := performRequest(router, "GET", "/") w := performRequest(router, "GET", "/")
// TEST // TEST
assert.Equal(t, 404, w.Code) assert.Equal(t, http.StatusNotFound, w.Code)
assert.Equal(t, "ACEGHFDB", signature) assert.Equal(t, "ACEGHFDB", signature)
} }
@ -110,7 +111,7 @@ func TestMiddlewareNoMethodEnabled(t *testing.T) {
w := performRequest(router, "GET", "/") w := performRequest(router, "GET", "/")
// TEST // TEST
assert.Equal(t, 405, w.Code) assert.Equal(t, http.StatusMethodNotAllowed, w.Code)
assert.Equal(t, "ACEGHFDB", signature) assert.Equal(t, "ACEGHFDB", signature)
} }
@ -147,7 +148,7 @@ func TestMiddlewareNoMethodDisabled(t *testing.T) {
w := performRequest(router, "GET", "/") w := performRequest(router, "GET", "/")
// TEST // TEST
assert.Equal(t, 404, w.Code) assert.Equal(t, http.StatusNotFound, w.Code)
assert.Equal(t, "AC X DB", signature) assert.Equal(t, "AC X DB", signature)
} }
@ -159,7 +160,7 @@ func TestMiddlewareAbort(t *testing.T) {
}) })
router.Use(func(c *Context) { router.Use(func(c *Context) {
signature += "C" signature += "C"
c.AbortWithStatus(401) c.AbortWithStatus(http.StatusUnauthorized)
c.Next() c.Next()
signature += "D" signature += "D"
}) })
@ -173,7 +174,7 @@ func TestMiddlewareAbort(t *testing.T) {
w := performRequest(router, "GET", "/") w := performRequest(router, "GET", "/")
// TEST // TEST
assert.Equal(t, 401, w.Code) assert.Equal(t, http.StatusUnauthorized, w.Code)
assert.Equal(t, "ACD", signature) assert.Equal(t, "ACD", signature)
} }
@ -183,7 +184,7 @@ func TestMiddlewareAbortHandlersChainAndNext(t *testing.T) {
router.Use(func(c *Context) { router.Use(func(c *Context) {
signature += "A" signature += "A"
c.Next() c.Next()
c.AbortWithStatus(410) c.AbortWithStatus(http.StatusGone)
signature += "B" signature += "B"
}) })
@ -195,7 +196,7 @@ func TestMiddlewareAbortHandlersChainAndNext(t *testing.T) {
w := performRequest(router, "GET", "/") w := performRequest(router, "GET", "/")
// TEST // TEST
assert.Equal(t, 410, w.Code) assert.Equal(t, http.StatusGone, w.Code)
assert.Equal(t, "ACB", signature) assert.Equal(t, "ACB", signature)
} }
@ -207,7 +208,7 @@ func TestMiddlewareFailHandlersChain(t *testing.T) {
router := New() router := New()
router.Use(func(context *Context) { router.Use(func(context *Context) {
signature += "A" signature += "A"
context.AbortWithError(500, errors.New("foo")) context.AbortWithError(http.StatusInternalServerError, errors.New("foo"))
}) })
router.Use(func(context *Context) { router.Use(func(context *Context) {
signature += "B" signature += "B"
@ -218,25 +219,25 @@ func TestMiddlewareFailHandlersChain(t *testing.T) {
w := performRequest(router, "GET", "/") w := performRequest(router, "GET", "/")
// TEST // TEST
assert.Equal(t, 500, w.Code) assert.Equal(t, http.StatusInternalServerError, w.Code)
assert.Equal(t, "A", signature) assert.Equal(t, "A", signature)
} }
func TestMiddlewareWrite(t *testing.T) { func TestMiddlewareWrite(t *testing.T) {
router := New() router := New()
router.Use(func(c *Context) { router.Use(func(c *Context) {
c.String(400, "hola\n") c.String(http.StatusBadRequest, "hola\n")
}) })
router.Use(func(c *Context) { router.Use(func(c *Context) {
c.XML(400, H{"foo": "bar"}) c.XML(http.StatusBadRequest, H{"foo": "bar"})
}) })
router.Use(func(c *Context) { router.Use(func(c *Context) {
c.JSON(400, H{"foo": "bar"}) c.JSON(http.StatusBadRequest, H{"foo": "bar"})
}) })
router.GET("/", func(c *Context) { router.GET("/", func(c *Context) {
c.JSON(400, H{"foo": "bar"}) c.JSON(http.StatusBadRequest, H{"foo": "bar"})
}, func(c *Context) { }, func(c *Context) {
c.Render(400, sse.Event{ c.Render(http.StatusBadRequest, sse.Event{
Event: "test", Event: "test",
Data: "message", Data: "message",
}) })
@ -244,6 +245,6 @@ func TestMiddlewareWrite(t *testing.T) {
w := performRequest(router, "GET", "/") w := performRequest(router, "GET", "/")
assert.Equal(t, 400, w.Code) assert.Equal(t, http.StatusBadRequest, w.Code)
assert.Equal(t, strings.Replace("hola\n<map><foo>bar</foo></map>{\"foo\":\"bar\"}{\"foo\":\"bar\"}event:test\ndata:message\n\n", " ", "", -1), strings.Replace(w.Body.String(), " ", "", -1)) assert.Equal(t, strings.Replace("hola\n<map><foo>bar</foo></map>{\"foo\":\"bar\"}{\"foo\":\"bar\"}event:test\ndata:message\n\n", " ", "", -1), strings.Replace(w.Body.String(), " ", "", -1))
} }

View File

@ -59,11 +59,11 @@ func cleanPath(p string) string {
case p[r] == '.' && p[r+1] == '/': case p[r] == '.' && p[r+1] == '/':
// . element // . element
r++ r += 2
case p[r] == '.' && p[r+1] == '.' && (r+2 == n || p[r+2] == '/'): case p[r] == '.' && p[r+1] == '.' && (r+2 == n || p[r+2] == '/'):
// .. element: remove to last / // .. element: remove to last /
r += 2 r += 3
if w > 1 { if w > 1 {
// can backtrack // can backtrack

View File

@ -6,6 +6,7 @@ package gin
import ( import (
"bytes" "bytes"
"net/http"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -22,7 +23,7 @@ func TestPanicInHandler(t *testing.T) {
// RUN // RUN
w := performRequest(router, "GET", "/recovery") w := performRequest(router, "GET", "/recovery")
// TEST // 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(), "GET /recovery")
assert.Contains(t, buffer.String(), "Oupps, Houston, we have a problem") assert.Contains(t, buffer.String(), "Oupps, Houston, we have a problem")
assert.Contains(t, buffer.String(), "TestPanicInHandler") assert.Contains(t, buffer.String(), "TestPanicInHandler")
@ -33,11 +34,31 @@ func TestPanicWithAbort(t *testing.T) {
router := New() router := New()
router.Use(RecoveryWithWriter(nil)) router.Use(RecoveryWithWriter(nil))
router.GET("/recovery", func(c *Context) { router.GET("/recovery", func(c *Context) {
c.AbortWithStatus(400) c.AbortWithStatus(http.StatusBadRequest)
panic("Oupps, Houston, we have a problem") panic("Oupps, Houston, we have a problem")
}) })
// RUN // RUN
w := performRequest(router, "GET", "/recovery") w := performRequest(router, "GET", "/recovery")
// TEST // TEST
assert.Equal(t, 400, w.Code) assert.Equal(t, http.StatusBadRequest, 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)
} }

View File

@ -16,6 +16,8 @@ type Redirect struct {
} }
func (r Redirect) Render(w http.ResponseWriter) error { 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 { if (r.Code < 300 || r.Code > 308) && r.Code != 201 {
panic(fmt.Sprintf("Cannot redirect with status code %d", r.Code)) panic(fmt.Sprintf("Cannot redirect with status code %d", r.Code))
} }

View File

@ -158,6 +158,21 @@ func TestRenderJsonpJSON(t *testing.T) {
assert.Equal(t, "application/javascript; charset=utf-8", w2.Header().Get("Content-Type")) 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) { func TestRenderJsonpJSONFail(t *testing.T) {
w := httptest.NewRecorder() w := httptest.NewRecorder()
data := make(chan int) data := make(chan int)
@ -271,7 +286,7 @@ func TestRenderRedirect(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
data1 := Redirect{ data1 := Redirect{
Code: 301, Code: http.StatusMovedPermanently,
Request: req, Request: req,
Location: "/new/location", Location: "/new/location",
} }
@ -281,7 +296,7 @@ func TestRenderRedirect(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
data2 := Redirect{ data2 := Redirect{
Code: 200, Code: http.StatusOK,
Request: req, Request: req,
Location: "/new/location", Location: "/new/location",
} }
@ -373,7 +388,7 @@ func TestRenderHTMLTemplateEmptyName(t *testing.T) {
func TestRenderHTMLDebugFiles(t *testing.T) { func TestRenderHTMLDebugFiles(t *testing.T) {
w := httptest.NewRecorder() w := httptest.NewRecorder()
htmlRender := HTMLDebug{Files: []string{"../fixtures/basic/hello.tmpl"}, htmlRender := HTMLDebug{Files: []string{"../testdata/template/hello.tmpl"},
Glob: "", Glob: "",
Delims: Delims{Left: "{[{", Right: "}]}"}, Delims: Delims{Left: "{[{", Right: "}]}"},
FuncMap: nil, FuncMap: nil,
@ -392,7 +407,7 @@ func TestRenderHTMLDebugFiles(t *testing.T) {
func TestRenderHTMLDebugGlob(t *testing.T) { func TestRenderHTMLDebugGlob(t *testing.T) {
w := httptest.NewRecorder() w := httptest.NewRecorder()
htmlRender := HTMLDebug{Files: nil, htmlRender := HTMLDebug{Files: nil,
Glob: "../fixtures/basic/hello*", Glob: "../testdata/template/hello*",
Delims: Delims{Left: "{[{", Right: "}]}"}, Delims: Delims{Left: "{[{", Right: "}]}"},
FuncMap: nil, FuncMap: nil,
} }

View File

@ -35,10 +35,10 @@ func TestResponseWriterReset(t *testing.T) {
writer.reset(testWritter) writer.reset(testWritter)
assert.Equal(t, -1, writer.size) 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, testWritter, writer.ResponseWriter)
assert.Equal(t, -1, w.Size()) assert.Equal(t, -1, w.Size())
assert.Equal(t, 200, w.Status()) assert.Equal(t, http.StatusOK, w.Status())
assert.False(t, w.Written()) assert.False(t, w.Written())
} }
@ -48,13 +48,13 @@ func TestResponseWriterWriteHeader(t *testing.T) {
writer.reset(testWritter) writer.reset(testWritter)
w := ResponseWriter(writer) w := ResponseWriter(writer)
w.WriteHeader(300) w.WriteHeader(http.StatusMultipleChoices)
assert.False(t, w.Written()) assert.False(t, w.Written())
assert.Equal(t, 300, w.Status()) assert.Equal(t, http.StatusMultipleChoices, w.Status())
assert.NotEqual(t, 300, testWritter.Code) assert.NotEqual(t, http.StatusMultipleChoices, testWritter.Code)
w.WriteHeader(-1) w.WriteHeader(-1)
assert.Equal(t, 300, w.Status()) assert.Equal(t, http.StatusMultipleChoices, w.Status())
} }
func TestResponseWriterWriteHeadersNow(t *testing.T) { func TestResponseWriterWriteHeadersNow(t *testing.T) {
@ -63,12 +63,12 @@ func TestResponseWriterWriteHeadersNow(t *testing.T) {
writer.reset(testWritter) writer.reset(testWritter)
w := ResponseWriter(writer) w := ResponseWriter(writer)
w.WriteHeader(300) w.WriteHeader(http.StatusMultipleChoices)
w.WriteHeaderNow() w.WriteHeaderNow()
assert.True(t, w.Written()) assert.True(t, w.Written())
assert.Equal(t, 0, w.Size()) assert.Equal(t, 0, w.Size())
assert.Equal(t, 300, testWritter.Code) assert.Equal(t, http.StatusMultipleChoices, testWritter.Code)
writer.size = 10 writer.size = 10
w.WriteHeaderNow() w.WriteHeaderNow()
@ -84,8 +84,8 @@ func TestResponseWriterWrite(t *testing.T) {
n, err := w.Write([]byte("hola")) n, err := w.Write([]byte("hola"))
assert.Equal(t, 4, n) assert.Equal(t, 4, n)
assert.Equal(t, 4, w.Size()) assert.Equal(t, 4, w.Size())
assert.Equal(t, 200, w.Status()) assert.Equal(t, http.StatusOK, w.Status())
assert.Equal(t, 200, testWritter.Code) assert.Equal(t, http.StatusOK, testWritter.Code)
assert.Equal(t, "hola", testWritter.Body.String()) assert.Equal(t, "hola", testWritter.Body.String())
assert.NoError(t, err) assert.NoError(t, err)

View File

@ -5,6 +5,7 @@
package gin package gin
import ( import (
"net/http"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -50,7 +51,7 @@ func performRequestInGroup(t *testing.T, method string) {
assert.Equal(t, "/v1/login/", login.BasePath()) assert.Equal(t, "/v1/login/", login.BasePath())
handler := func(c *Context) { 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 { switch method {
@ -80,11 +81,11 @@ func performRequestInGroup(t *testing.T, method string) {
} }
w := performRequest(router, method, "/v1/login/test") 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()) assert.Equal(t, "the method was "+method+" and index 3", w.Body.String())
w = performRequest(router, method, "/v1/test") 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()) assert.Equal(t, "the method was "+method+" and index 1", w.Body.String())
} }

View File

@ -80,20 +80,20 @@ func testRouteNotOK2(method string, t *testing.T) {
func TestRouterMethod(t *testing.T) { func TestRouterMethod(t *testing.T) {
router := New() router := New()
router.PUT("/hey2", func(c *Context) { router.PUT("/hey2", func(c *Context) {
c.String(200, "sup2") c.String(http.StatusOK, "sup2")
}) })
router.PUT("/hey", func(c *Context) { router.PUT("/hey", func(c *Context) {
c.String(200, "called") c.String(http.StatusOK, "called")
}) })
router.PUT("/hey3", func(c *Context) { router.PUT("/hey3", func(c *Context) {
c.String(200, "sup3") c.String(http.StatusOK, "sup3")
}) })
w := performRequest(router, "PUT", "/hey") 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()) assert.Equal(t, "called", w.Body.String())
} }
@ -144,42 +144,42 @@ func TestRouteRedirectTrailingSlash(t *testing.T) {
w := performRequest(router, "GET", "/path/") w := performRequest(router, "GET", "/path/")
assert.Equal(t, "/path", w.Header().Get("Location")) 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") w = performRequest(router, "GET", "/path2")
assert.Equal(t, "/path2/", w.Header().Get("Location")) 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/") w = performRequest(router, "POST", "/path3/")
assert.Equal(t, "/path3", w.Header().Get("Location")) 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") w = performRequest(router, "PUT", "/path4")
assert.Equal(t, "/path4/", w.Header().Get("Location")) 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") w = performRequest(router, "GET", "/path")
assert.Equal(t, 200, w.Code) assert.Equal(t, http.StatusOK, w.Code)
w = performRequest(router, "GET", "/path2/") w = performRequest(router, "GET", "/path2/")
assert.Equal(t, 200, w.Code) assert.Equal(t, http.StatusOK, w.Code)
w = performRequest(router, "POST", "/path3") w = performRequest(router, "POST", "/path3")
assert.Equal(t, 200, w.Code) assert.Equal(t, http.StatusOK, w.Code)
w = performRequest(router, "PUT", "/path4/") w = performRequest(router, "PUT", "/path4/")
assert.Equal(t, 200, w.Code) assert.Equal(t, http.StatusOK, w.Code)
router.RedirectTrailingSlash = false router.RedirectTrailingSlash = false
w = performRequest(router, "GET", "/path/") w = performRequest(router, "GET", "/path/")
assert.Equal(t, 404, w.Code) assert.Equal(t, http.StatusNotFound, w.Code)
w = performRequest(router, "GET", "/path2") w = performRequest(router, "GET", "/path2")
assert.Equal(t, 404, w.Code) assert.Equal(t, http.StatusNotFound, w.Code)
w = performRequest(router, "POST", "/path3/") w = performRequest(router, "POST", "/path3/")
assert.Equal(t, 404, w.Code) assert.Equal(t, http.StatusNotFound, w.Code)
w = performRequest(router, "PUT", "/path4") w = performRequest(router, "PUT", "/path4")
assert.Equal(t, 404, w.Code) assert.Equal(t, http.StatusNotFound, w.Code)
} }
func TestRouteRedirectFixedPath(t *testing.T) { func TestRouteRedirectFixedPath(t *testing.T) {
@ -194,19 +194,19 @@ func TestRouteRedirectFixedPath(t *testing.T) {
w := performRequest(router, "GET", "/PATH") w := performRequest(router, "GET", "/PATH")
assert.Equal(t, "/path", w.Header().Get("Location")) 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") w = performRequest(router, "GET", "/path2")
assert.Equal(t, "/Path2", w.Header().Get("Location")) 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") w = performRequest(router, "POST", "/path3")
assert.Equal(t, "/PATH3", w.Header().Get("Location")) 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") w = performRequest(router, "POST", "/path4")
assert.Equal(t, "/Path4/", w.Header().Get("Location")) 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. // 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") 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, "john", name)
assert.Equal(t, "smith", lastName) assert.Equal(t, "smith", lastName)
assert.Equal(t, "/is/super/great", wild) assert.Equal(t, "/is/super/great", wild)
@ -265,7 +265,7 @@ func TestRouteStaticFile(t *testing.T) {
w2 := performRequest(router, "GET", "/result") w2 := performRequest(router, "GET", "/result")
assert.Equal(t, w, w2) 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, "Gin Web Framework", w.Body.String())
assert.Equal(t, "text/plain; charset=utf-8", w.HeaderMap.Get("Content-Type")) 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") w4 := performRequest(router, "HEAD", "/result")
assert.Equal(t, w3, w4) 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 // TestHandleStaticDir - ensure the root/sub dir handles properly
@ -283,7 +283,7 @@ func TestRouteStaticListingDir(t *testing.T) {
w := performRequest(router, "GET", "/") 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.Contains(t, w.Body.String(), "gin.go")
assert.Equal(t, "text/html; charset=utf-8", w.HeaderMap.Get("Content-Type")) 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", "/") 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") assert.NotContains(t, w.Body.String(), "gin.go")
} }
@ -310,7 +310,7 @@ func TestRouterMiddlewareAndStatic(t *testing.T) {
w := performRequest(router, "GET", "/gin.go") 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.Contains(t, w.Body.String(), "package gin")
assert.Equal(t, "text/plain; charset=utf-8", w.HeaderMap.Get("Content-Type")) 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") assert.NotEqual(t, w.HeaderMap.Get("Last-Modified"), "Mon, 02 Jan 2006 15:04:05 MST")
@ -333,19 +333,29 @@ func TestRouteNotAllowedEnabled(t *testing.T) {
assert.Equal(t, http.StatusTeapot, w.Code) 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) { func TestRouteNotAllowedDisabled(t *testing.T) {
router := New() router := New()
router.HandleMethodNotAllowed = false router.HandleMethodNotAllowed = false
router.POST("/path", func(c *Context) {}) router.POST("/path", func(c *Context) {})
w := performRequest(router, "GET", "/path") w := performRequest(router, "GET", "/path")
assert.Equal(t, 404, w.Code) assert.Equal(t, http.StatusNotFound, w.Code)
router.NoMethod(func(c *Context) { router.NoMethod(func(c *Context) {
c.String(http.StatusTeapot, "responseText") c.String(http.StatusTeapot, "responseText")
}) })
w = performRequest(router, "GET", "/path") w = performRequest(router, "GET", "/path")
assert.Equal(t, "404 page not found", w.Body.String()) 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) { func TestRouterNotFound(t *testing.T) {
@ -360,20 +370,20 @@ func TestRouterNotFound(t *testing.T) {
code int code int
location string location string
}{ }{
{"/path/", 301, "/path"}, // TSR -/ {"/path/", http.StatusMovedPermanently, "/path"}, // TSR -/
{"/dir", 301, "/dir/"}, // TSR +/ {"/dir", http.StatusMovedPermanently, "/dir/"}, // TSR +/
{"", 301, "/"}, // TSR +/ {"", http.StatusMovedPermanently, "/"}, // TSR +/
{"/PATH", 301, "/path"}, // Fixed Case {"/PATH", http.StatusMovedPermanently, "/path"}, // Fixed Case
{"/DIR/", 301, "/dir/"}, // Fixed Case {"/DIR/", http.StatusMovedPermanently, "/dir/"}, // Fixed Case
{"/PATH/", 301, "/path"}, // Fixed Case -/ {"/PATH/", http.StatusMovedPermanently, "/path"}, // Fixed Case -/
{"/DIR", 301, "/dir/"}, // Fixed Case +/ {"/DIR", http.StatusMovedPermanently, "/dir/"}, // Fixed Case +/
{"/../path", 301, "/path"}, // CleanPath {"/../path", http.StatusMovedPermanently, "/path"}, // CleanPath
{"/nope", 404, ""}, // NotFound {"/nope", http.StatusNotFound, ""}, // NotFound
} }
for _, tr := range testRoutes { for _, tr := range testRoutes {
w := performRequest(router, "GET", tr.route) w := performRequest(router, "GET", tr.route)
assert.Equal(t, tr.code, w.Code) 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"))) assert.Equal(t, tr.location, fmt.Sprint(w.Header().Get("Location")))
} }
} }
@ -381,24 +391,24 @@ func TestRouterNotFound(t *testing.T) {
// Test custom not found handler // Test custom not found handler
var notFound bool var notFound bool
router.NoRoute(func(c *Context) { router.NoRoute(func(c *Context) {
c.AbortWithStatus(404) c.AbortWithStatus(http.StatusNotFound)
notFound = true notFound = true
}) })
w := performRequest(router, "GET", "/nope") w := performRequest(router, "GET", "/nope")
assert.Equal(t, 404, w.Code) assert.Equal(t, http.StatusNotFound, w.Code)
assert.True(t, notFound) assert.True(t, notFound)
// Test other method than GET (want 307 instead of 301) // Test other method than GET (want 307 instead of 301)
router.PATCH("/path", func(c *Context) {}) router.PATCH("/path", func(c *Context) {})
w = performRequest(router, "PATCH", "/path/") 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())) assert.Equal(t, "map[Location:[/path]]", fmt.Sprint(w.Header()))
// Test special case where no node for the prefix "/" exists // Test special case where no node for the prefix "/" exists
router = New() router = New()
router.GET("/a", func(c *Context) {}) router.GET("/a", func(c *Context) {})
w = performRequest(router, "GET", "/") w = performRequest(router, "GET", "/")
assert.Equal(t, 404, w.Code) assert.Equal(t, http.StatusNotFound, w.Code)
} }
func TestRouteRawPath(t *testing.T) { func TestRouteRawPath(t *testing.T) {
@ -417,7 +427,7 @@ func TestRouteRawPath(t *testing.T) {
}) })
w := performRequest(route, "POST", "/project/Some%2FOther%2FProject/build/222") 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) { func TestRouteRawPathNoUnescape(t *testing.T) {
@ -437,7 +447,7 @@ func TestRouteRawPathNoUnescape(t *testing.T) {
}) })
w := performRequest(route, "POST", "/project/Some%2FOther%2FProject/build/333") 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) { func TestRouteServeErrorWithWriteHeader(t *testing.T) {

View File

@ -4,10 +4,7 @@
package gin package gin
import ( import "net/http"
"net/http"
"net/http/httptest"
)
// CreateTestContext returns a fresh engine and context for testing purposes // CreateTestContext returns a fresh engine and context for testing purposes
func CreateTestContext(w http.ResponseWriter) (c *Context, r *Engine) { 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) c.writermem.reset(w)
return 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),
}
}

View File

@ -3,7 +3,7 @@
// DO NOT EDIT! // 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: It is generated from these files:
test.proto test.proto
@ -11,7 +11,7 @@ It is generated from these files:
It has these top-level messages: It has these top-level messages:
Test Test
*/ */
package example package protoexample
import proto "github.com/golang/protobuf/proto" import proto "github.com/golang/protobuf/proto"
import math "math" import math "math"
@ -109,5 +109,5 @@ func (m *Test_OptionalGroup) GetRequiredField() string {
} }
func init() { func init() {
proto.RegisterEnum("example.FOO", FOO_name, FOO_value) proto.RegisterEnum("protoexample.FOO", FOO_name, FOO_value)
} }

View File

@ -1,4 +1,4 @@
package example; package protoexample;
enum FOO {X=17;}; enum FOO {X=17;};

View File

@ -5,6 +5,8 @@
package gin package gin
import ( import (
"bytes"
"encoding/xml"
"fmt" "fmt"
"net/http" "net/http"
"testing" "testing"
@ -23,7 +25,7 @@ type testStruct struct {
func (t *testStruct) ServeHTTP(w http.ResponseWriter, req *http.Request) { func (t *testStruct) ServeHTTP(w http.ResponseWriter, req *http.Request) {
assert.Equal(t.T, "POST", req.Method) assert.Equal(t.T, "POST", req.Method)
assert.Equal(t.T, "/path", req.URL.Path) assert.Equal(t.T, "/path", req.URL.Path)
w.WriteHeader(500) w.WriteHeader(http.StatusInternalServerError)
fmt.Fprint(w, "hello") fmt.Fprint(w, "hello")
} }
@ -33,16 +35,16 @@ func TestWrap(t *testing.T) {
router.GET("/path2", WrapF(func(w http.ResponseWriter, req *http.Request) { router.GET("/path2", WrapF(func(w http.ResponseWriter, req *http.Request) {
assert.Equal(t, "GET", req.Method) assert.Equal(t, "GET", req.Method)
assert.Equal(t, "/path2", req.URL.Path) assert.Equal(t, "/path2", req.URL.Path)
w.WriteHeader(400) w.WriteHeader(http.StatusBadRequest)
fmt.Fprint(w, "hola!") fmt.Fprint(w, "hola!")
})) }))
w := performRequest(router, "POST", "/path") 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()) assert.Equal(t, "hello", w.Body.String())
w = performRequest(router, "GET", "/path2") 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()) assert.Equal(t, "hola!", w.Body.String())
} }
@ -124,3 +126,14 @@ func TestBindMiddleware(t *testing.T) {
Bind(&bindTestStruct{}) 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)
}