forked from mirror/gin
Tons of unit tests
This commit is contained in:
parent
ac1ee3fb86
commit
0a192fb0fa
|
@ -1,2 +1,4 @@
|
|||
Godeps/*
|
||||
!Godeps/Godeps.json
|
||||
coverage.out
|
||||
count.out
|
||||
|
|
|
@ -73,6 +73,10 @@ func TestBasicAuthSearchCredential(t *testing.T) {
|
|||
user, found = pairs.searchCredential(authorizationHeader("foo", "bar "))
|
||||
assert.Empty(t, user)
|
||||
assert.False(t, found)
|
||||
|
||||
user, found = pairs.searchCredential("")
|
||||
assert.Empty(t, user)
|
||||
assert.False(t, found)
|
||||
}
|
||||
|
||||
func TestBasicAuthAuthorizationHeader(t *testing.T) {
|
||||
|
|
|
@ -50,3 +50,10 @@ func Default(method, contentType string) Binding {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Validate(obj interface{}) error {
|
||||
if err := _validator.ValidateStruct(obj); err != nil {
|
||||
return error(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package binding
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type FooStruct struct {
|
||||
Foo string `json:"foo" form:"foo" xml:"foo" binding:"required"`
|
||||
}
|
||||
|
||||
func TestBindingDefault(t *testing.T) {
|
||||
assert.Equal(t, Default("GET", ""), GETForm)
|
||||
assert.Equal(t, Default("GET", MIMEJSON), GETForm)
|
||||
|
||||
assert.Equal(t, Default("POST", MIMEJSON), JSON)
|
||||
assert.Equal(t, Default("PUT", MIMEJSON), JSON)
|
||||
|
||||
assert.Equal(t, Default("POST", MIMEXML), XML)
|
||||
assert.Equal(t, Default("PUT", MIMEXML2), XML)
|
||||
|
||||
assert.Equal(t, Default("POST", MIMEPOSTForm), POSTForm)
|
||||
assert.Equal(t, Default("DELETE", MIMEPOSTForm), POSTForm)
|
||||
}
|
||||
|
||||
func TestBindingJSON(t *testing.T) {
|
||||
testBinding(t,
|
||||
JSON, "json",
|
||||
"/", "/",
|
||||
`{"foo": "bar"}`, `{"bar": "foo"}`)
|
||||
}
|
||||
|
||||
func TestBindingPOSTForm(t *testing.T) {
|
||||
testBinding(t,
|
||||
POSTForm, "post_form",
|
||||
"/", "/",
|
||||
"foo=bar", "bar=foo")
|
||||
}
|
||||
|
||||
func TestBindingGETForm(t *testing.T) {
|
||||
testBinding(t,
|
||||
GETForm, "get_form",
|
||||
"/?foo=bar", "/?bar=foo",
|
||||
"", "")
|
||||
}
|
||||
|
||||
func TestBindingXML(t *testing.T) {
|
||||
testBinding(t,
|
||||
XML, "xml",
|
||||
"/", "/",
|
||||
"<map><foo>bar</foo></map>", "<map><bar>foo</bar></map>")
|
||||
}
|
||||
|
||||
func testBinding(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
|
||||
assert.Equal(t, b.Name(), name)
|
||||
|
||||
obj := FooStruct{}
|
||||
req := requestWithBody(path, body)
|
||||
err := b.Bind(req, &obj)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, obj.Foo, "bar")
|
||||
|
||||
obj = FooStruct{}
|
||||
req = requestWithBody(badPath, badBody)
|
||||
err = JSON.Bind(req, &obj)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func requestWithBody(path, body string) (req *http.Request) {
|
||||
req, _ = http.NewRequest("POST", path, bytes.NewBufferString(body))
|
||||
return
|
||||
}
|
|
@ -19,8 +19,5 @@ func (_ getFormBinding) Bind(req *http.Request, obj interface{}) error {
|
|||
if err := mapForm(obj, req.Form); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := _validator.ValidateStruct(obj); err != nil {
|
||||
return error(err)
|
||||
}
|
||||
return nil
|
||||
return Validate(obj)
|
||||
}
|
||||
|
|
|
@ -21,8 +21,5 @@ func (_ jsonBinding) Bind(req *http.Request, obj interface{}) error {
|
|||
if err := decoder.Decode(obj); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := _validator.ValidateStruct(obj); err != nil {
|
||||
return error(err)
|
||||
}
|
||||
return nil
|
||||
return Validate(obj)
|
||||
}
|
||||
|
|
|
@ -19,8 +19,5 @@ func (_ postFormBinding) Bind(req *http.Request, obj interface{}) error {
|
|||
if err := mapForm(obj, req.PostForm); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := _validator.ValidateStruct(obj); err != nil {
|
||||
return error(err)
|
||||
}
|
||||
return nil
|
||||
return Validate(obj)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package binding
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type struct1 struct {
|
||||
Value float64 `binding:"required"`
|
||||
}
|
||||
|
||||
type struct2 struct {
|
||||
RequiredValue string `binding:"required"`
|
||||
Value float64
|
||||
}
|
||||
|
||||
type struct3 struct {
|
||||
Integer int
|
||||
String string
|
||||
BasicSlice []int
|
||||
Boolean bool
|
||||
|
||||
RequiredInteger int `binding:"required"`
|
||||
RequiredString string `binding:"required"`
|
||||
RequiredAnotherStruct struct1 `binding:"required"`
|
||||
RequiredBasicSlice []int `binding:"required"`
|
||||
RequiredComplexSlice []struct2 `binding:"required"`
|
||||
RequiredBoolean bool `binding:"required"`
|
||||
}
|
||||
|
||||
func createStruct() struct3 {
|
||||
return struct3{
|
||||
RequiredInteger: 2,
|
||||
RequiredString: "hello",
|
||||
RequiredAnotherStruct: struct1{1.5},
|
||||
RequiredBasicSlice: []int{1, 2, 3, 4},
|
||||
RequiredComplexSlice: []struct2{
|
||||
{RequiredValue: "A"},
|
||||
{RequiredValue: "B"},
|
||||
},
|
||||
RequiredBoolean: true,
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateGoodObject(t *testing.T) {
|
||||
test := createStruct()
|
||||
assert.Nil(t, Validate(&test))
|
||||
}
|
|
@ -20,8 +20,5 @@ func (_ xmlBinding) Bind(req *http.Request, obj interface{}) error {
|
|||
if err := decoder.Decode(obj); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := _validator.ValidateStruct(obj); err != nil {
|
||||
return error(err)
|
||||
}
|
||||
return nil
|
||||
return Validate(obj)
|
||||
}
|
||||
|
|
|
@ -61,6 +61,9 @@ func (c *Context) reset() {
|
|||
|
||||
func (c *Context) Copy() *Context {
|
||||
var cp Context = *c
|
||||
cp.writermem.ResponseWriter = nil
|
||||
cp.Writer = &cp.writermem
|
||||
cp.Input.context = &cp
|
||||
cp.index = AbortIndex
|
||||
cp.handlers = nil
|
||||
return &cp
|
||||
|
@ -161,7 +164,7 @@ func (c *Context) MustGet(key string) interface{} {
|
|||
if value, exists := c.Get(key); exists {
|
||||
return value
|
||||
} else {
|
||||
panic("Key " + key + " does not exist")
|
||||
panic("Key \"" + key + "\" does not exist")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,11 @@ import (
|
|||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// Unit tes TODO
|
||||
// func (c *Context) File(filepath string) {
|
||||
// func (c *Context) Negotiate(code int, config Negotiate) {
|
||||
// BAD case: func (c *Context) Render(code int, render render.Render, obj ...interface{}) {
|
||||
|
||||
func createTestContext() (c *Context, w *httptest.ResponseRecorder, r *Engine) {
|
||||
w = httptest.NewRecorder()
|
||||
r = New()
|
||||
|
@ -64,6 +69,25 @@ func TestContextSetGet(t *testing.T) {
|
|||
assert.Panics(t, func() { c.MustGet("no_exist") })
|
||||
}
|
||||
|
||||
func TestContextCopy(t *testing.T) {
|
||||
c, _, _ := createTestContext()
|
||||
c.index = 2
|
||||
c.Request, _ = http.NewRequest("POST", "/hola", nil)
|
||||
c.handlers = []HandlerFunc{func(c *Context) {}}
|
||||
c.Params = Params{Param{Key: "foo", Value: "bar"}}
|
||||
c.Set("foo", "bar")
|
||||
|
||||
cp := c.Copy()
|
||||
assert.Nil(t, cp.handlers)
|
||||
assert.Equal(t, cp.Request, c.Request)
|
||||
assert.Equal(t, cp.index, AbortIndex)
|
||||
assert.Equal(t, &cp.writermem, cp.Writer.(*responseWriter))
|
||||
assert.Equal(t, cp.Input.context, cp)
|
||||
assert.Equal(t, cp.Keys, c.Keys)
|
||||
assert.Equal(t, cp.Engine, c.Engine)
|
||||
assert.Equal(t, cp.Params, c.Params)
|
||||
}
|
||||
|
||||
// Tests that the response is serialized as JSON
|
||||
// and Content-Type is set to application/json
|
||||
func TestContextRenderJSON(t *testing.T) {
|
||||
|
@ -79,7 +103,7 @@ func TestContextRenderJSON(t *testing.T) {
|
|||
// and responds with Content-Type set to text/html
|
||||
func TestContextRenderHTML(t *testing.T) {
|
||||
c, w, router := createTestContext()
|
||||
templ, _ := template.New("t").Parse(`Hello {{.name}}`)
|
||||
templ := template.Must(template.New("t").Parse(`Hello {{.name}}`))
|
||||
router.SetHTMLTemplate(templ)
|
||||
|
||||
c.HTML(201, "t", H{"name": "alexandernyquist"})
|
||||
|
@ -160,6 +184,7 @@ func TestContextNegotiationFormat(t *testing.T) {
|
|||
c, _, _ := createTestContext()
|
||||
c.Request, _ = http.NewRequest("POST", "", nil)
|
||||
|
||||
assert.Panics(t, func() { c.NegotiateFormat() })
|
||||
assert.Equal(t, c.NegotiateFormat(MIMEJSON, MIMEXML), MIMEJSON)
|
||||
assert.Equal(t, c.NegotiateFormat(MIMEHTML, MIMEJSON), MIMEHTML)
|
||||
}
|
||||
|
@ -203,13 +228,19 @@ func TestContextAbortWithStatus(t *testing.T) {
|
|||
|
||||
func TestContextError(t *testing.T) {
|
||||
c, _, _ := createTestContext()
|
||||
assert.Nil(t, c.LastError())
|
||||
assert.Empty(t, c.Errors.String())
|
||||
|
||||
c.Error(errors.New("first error"), "some data")
|
||||
assert.Equal(t, c.LastError().Error(), "first error")
|
||||
assert.Len(t, c.Errors, 1)
|
||||
assert.Equal(t, c.Errors.String(), "Error #01: first error\n Meta: some data\n")
|
||||
|
||||
c.Error(errors.New("second error"), "some data 2")
|
||||
assert.Equal(t, c.LastError().Error(), "second error")
|
||||
assert.Len(t, c.Errors, 2)
|
||||
assert.Equal(t, c.Errors.String(), "Error #01: first error\n Meta: some data\n"+
|
||||
"Error #02: second error\n Meta: some data 2\n")
|
||||
|
||||
assert.Equal(t, c.Errors[0].Err, "first error")
|
||||
assert.Equal(t, c.Errors[0].Meta, "some data")
|
||||
|
|
|
@ -10,6 +10,10 @@ import (
|
|||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// TODO
|
||||
// func debugRoute(httpMethod, absolutePath string, handlers []HandlerFunc) {
|
||||
// func debugPrint(format string, values ...interface{}) {
|
||||
|
||||
func TestIsDebugging(t *testing.T) {
|
||||
SetMode(DebugMode)
|
||||
assert.True(t, IsDebugging())
|
||||
|
|
|
@ -43,7 +43,7 @@ func (a errorMsgs) String() string {
|
|||
}
|
||||
var buffer bytes.Buffer
|
||||
for i, msg := range a {
|
||||
text := fmt.Sprintf("Error #%02d: %s \n Meta: %v\n", (i + 1), msg.Err, msg.Meta)
|
||||
text := fmt.Sprintf("Error #%02d: %s\n Meta: %v\n", (i + 1), msg.Err, msg.Meta)
|
||||
buffer.WriteString(text)
|
||||
}
|
||||
return buffer.String()
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/flosch/pongo2"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gin-gonic/gin/render"
|
||||
)
|
||||
|
||||
func main() {
|
||||
router := gin.Default()
|
||||
router.HTMLRender = newPongoRender()
|
||||
|
||||
router.GET("/index", func(c *gin.Context) {
|
||||
c.HTML(200, "index.html", gin.H{
|
||||
"title": "Gin meets pongo2 !",
|
||||
"name": c.Input.Get("name"),
|
||||
})
|
||||
})
|
||||
router.Run(":8080")
|
||||
}
|
||||
|
||||
type pongoRender struct {
|
||||
cache map[string]*pongo2.Template
|
||||
}
|
||||
|
||||
func newPongoRender() *pongoRender {
|
||||
return &pongoRender{map[string]*pongo2.Template{}}
|
||||
}
|
||||
|
||||
func (p *pongoRender) Render(w http.ResponseWriter, code int, data ...interface{}) error {
|
||||
file := data[0].(string)
|
||||
ctx := data[1].(pongo2.Context)
|
||||
var t *pongo2.Template
|
||||
|
||||
if tmpl, ok := p.cache[file]; ok {
|
||||
t = tmpl
|
||||
} else {
|
||||
tmpl, err := pongo2.FromFile(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.cache[file] = tmpl
|
||||
t = tmpl
|
||||
}
|
||||
render.WriteHeader(w, code, "text/html")
|
||||
return t.ExecuteWriter(ctx, w)
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="ja">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>{{ title }}</title>
|
||||
<meta name="keywords" content="">
|
||||
<meta name="description" content="">
|
||||
</head>
|
||||
<body>
|
||||
Hello {{ name }} !
|
||||
</body>
|
||||
</html>
|
7
gin.go
7
gin.go
|
@ -144,6 +144,13 @@ func (engine *Engine) handle(method, path string, handlers []HandlerFunc) {
|
|||
if path[0] != '/' {
|
||||
panic("path must begin with '/'")
|
||||
}
|
||||
if method == "" {
|
||||
panic("HTTP method can not be empty")
|
||||
}
|
||||
if len(handlers) == 0 {
|
||||
panic("there must be at least one handler")
|
||||
}
|
||||
|
||||
root := engine.trees[method]
|
||||
if root == nil {
|
||||
root = new(node)
|
||||
|
|
12
gin_test.go
12
gin_test.go
|
@ -10,6 +10,12 @@ import (
|
|||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
//TODO
|
||||
// func (engine *Engine) LoadHTMLGlob(pattern string) {
|
||||
// func (engine *Engine) LoadHTMLFiles(files ...string) {
|
||||
// func (engine *Engine) Run(addr string) error {
|
||||
// func (engine *Engine) RunTLS(addr string, cert string, key string) error {
|
||||
|
||||
func init() {
|
||||
SetMode(TestMode)
|
||||
}
|
||||
|
@ -20,9 +26,9 @@ func TestCreateEngine(t *testing.T) {
|
|||
assert.Equal(t, router.engine, router)
|
||||
assert.Empty(t, router.Handlers)
|
||||
|
||||
// TODO
|
||||
// assert.Equal(t, router.router.NotFound, router.handle404)
|
||||
// assert.Equal(t, router.router.MethodNotAllowed, router.handle405)
|
||||
assert.Panics(t, func() { router.handle("", "/", []HandlerFunc{func(_ *Context) {}}) })
|
||||
assert.Panics(t, func() { router.handle("GET", "", []HandlerFunc{func(_ *Context) {}}) })
|
||||
assert.Panics(t, func() { router.handle("GET", "/", []HandlerFunc{}) })
|
||||
}
|
||||
|
||||
func TestCreateDefaultRouter(t *testing.T) {
|
||||
|
|
|
@ -0,0 +1,344 @@
|
|||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package gin
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type route struct {
|
||||
method string
|
||||
path string
|
||||
}
|
||||
|
||||
// http://developer.github.com/v3/
|
||||
var githubAPI = []route{
|
||||
// OAuth Authorizations
|
||||
{"GET", "/authorizations"},
|
||||
{"GET", "/authorizations/:id"},
|
||||
{"POST", "/authorizations"},
|
||||
//{"PUT", "/authorizations/clients/:client_id"},
|
||||
//{"PATCH", "/authorizations/:id"},
|
||||
{"DELETE", "/authorizations/:id"},
|
||||
{"GET", "/applications/:client_id/tokens/:access_token"},
|
||||
{"DELETE", "/applications/:client_id/tokens"},
|
||||
{"DELETE", "/applications/:client_id/tokens/:access_token"},
|
||||
|
||||
// Activity
|
||||
{"GET", "/events"},
|
||||
{"GET", "/repos/:owner/:repo/events"},
|
||||
{"GET", "/networks/:owner/:repo/events"},
|
||||
{"GET", "/orgs/:org/events"},
|
||||
{"GET", "/users/:user/received_events"},
|
||||
{"GET", "/users/:user/received_events/public"},
|
||||
{"GET", "/users/:user/events"},
|
||||
{"GET", "/users/:user/events/public"},
|
||||
{"GET", "/users/:user/events/orgs/:org"},
|
||||
{"GET", "/feeds"},
|
||||
{"GET", "/notifications"},
|
||||
{"GET", "/repos/:owner/:repo/notifications"},
|
||||
{"PUT", "/notifications"},
|
||||
{"PUT", "/repos/:owner/:repo/notifications"},
|
||||
{"GET", "/notifications/threads/:id"},
|
||||
//{"PATCH", "/notifications/threads/:id"},
|
||||
{"GET", "/notifications/threads/:id/subscription"},
|
||||
{"PUT", "/notifications/threads/:id/subscription"},
|
||||
{"DELETE", "/notifications/threads/:id/subscription"},
|
||||
{"GET", "/repos/:owner/:repo/stargazers"},
|
||||
{"GET", "/users/:user/starred"},
|
||||
{"GET", "/user/starred"},
|
||||
{"GET", "/user/starred/:owner/:repo"},
|
||||
{"PUT", "/user/starred/:owner/:repo"},
|
||||
{"DELETE", "/user/starred/:owner/:repo"},
|
||||
{"GET", "/repos/:owner/:repo/subscribers"},
|
||||
{"GET", "/users/:user/subscriptions"},
|
||||
{"GET", "/user/subscriptions"},
|
||||
{"GET", "/repos/:owner/:repo/subscription"},
|
||||
{"PUT", "/repos/:owner/:repo/subscription"},
|
||||
{"DELETE", "/repos/:owner/:repo/subscription"},
|
||||
{"GET", "/user/subscriptions/:owner/:repo"},
|
||||
{"PUT", "/user/subscriptions/:owner/:repo"},
|
||||
{"DELETE", "/user/subscriptions/:owner/:repo"},
|
||||
|
||||
// Gists
|
||||
{"GET", "/users/:user/gists"},
|
||||
{"GET", "/gists"},
|
||||
//{"GET", "/gists/public"},
|
||||
//{"GET", "/gists/starred"},
|
||||
{"GET", "/gists/:id"},
|
||||
{"POST", "/gists"},
|
||||
//{"PATCH", "/gists/:id"},
|
||||
{"PUT", "/gists/:id/star"},
|
||||
{"DELETE", "/gists/:id/star"},
|
||||
{"GET", "/gists/:id/star"},
|
||||
{"POST", "/gists/:id/forks"},
|
||||
{"DELETE", "/gists/:id"},
|
||||
|
||||
// Git Data
|
||||
{"GET", "/repos/:owner/:repo/git/blobs/:sha"},
|
||||
{"POST", "/repos/:owner/:repo/git/blobs"},
|
||||
{"GET", "/repos/:owner/:repo/git/commits/:sha"},
|
||||
{"POST", "/repos/:owner/:repo/git/commits"},
|
||||
//{"GET", "/repos/:owner/:repo/git/refs/*ref"},
|
||||
{"GET", "/repos/:owner/:repo/git/refs"},
|
||||
{"POST", "/repos/:owner/:repo/git/refs"},
|
||||
//{"PATCH", "/repos/:owner/:repo/git/refs/*ref"},
|
||||
//{"DELETE", "/repos/:owner/:repo/git/refs/*ref"},
|
||||
{"GET", "/repos/:owner/:repo/git/tags/:sha"},
|
||||
{"POST", "/repos/:owner/:repo/git/tags"},
|
||||
{"GET", "/repos/:owner/:repo/git/trees/:sha"},
|
||||
{"POST", "/repos/:owner/:repo/git/trees"},
|
||||
|
||||
// Issues
|
||||
{"GET", "/issues"},
|
||||
{"GET", "/user/issues"},
|
||||
{"GET", "/orgs/:org/issues"},
|
||||
{"GET", "/repos/:owner/:repo/issues"},
|
||||
{"GET", "/repos/:owner/:repo/issues/:number"},
|
||||
{"POST", "/repos/:owner/:repo/issues"},
|
||||
//{"PATCH", "/repos/:owner/:repo/issues/:number"},
|
||||
{"GET", "/repos/:owner/:repo/assignees"},
|
||||
{"GET", "/repos/:owner/:repo/assignees/:assignee"},
|
||||
{"GET", "/repos/:owner/:repo/issues/:number/comments"},
|
||||
//{"GET", "/repos/:owner/:repo/issues/comments"},
|
||||
//{"GET", "/repos/:owner/:repo/issues/comments/:id"},
|
||||
{"POST", "/repos/:owner/:repo/issues/:number/comments"},
|
||||
//{"PATCH", "/repos/:owner/:repo/issues/comments/:id"},
|
||||
//{"DELETE", "/repos/:owner/:repo/issues/comments/:id"},
|
||||
{"GET", "/repos/:owner/:repo/issues/:number/events"},
|
||||
//{"GET", "/repos/:owner/:repo/issues/events"},
|
||||
//{"GET", "/repos/:owner/:repo/issues/events/:id"},
|
||||
{"GET", "/repos/:owner/:repo/labels"},
|
||||
{"GET", "/repos/:owner/:repo/labels/:name"},
|
||||
{"POST", "/repos/:owner/:repo/labels"},
|
||||
//{"PATCH", "/repos/:owner/:repo/labels/:name"},
|
||||
{"DELETE", "/repos/:owner/:repo/labels/:name"},
|
||||
{"GET", "/repos/:owner/:repo/issues/:number/labels"},
|
||||
{"POST", "/repos/:owner/:repo/issues/:number/labels"},
|
||||
{"DELETE", "/repos/:owner/:repo/issues/:number/labels/:name"},
|
||||
{"PUT", "/repos/:owner/:repo/issues/:number/labels"},
|
||||
{"DELETE", "/repos/:owner/:repo/issues/:number/labels"},
|
||||
{"GET", "/repos/:owner/:repo/milestones/:number/labels"},
|
||||
{"GET", "/repos/:owner/:repo/milestones"},
|
||||
{"GET", "/repos/:owner/:repo/milestones/:number"},
|
||||
{"POST", "/repos/:owner/:repo/milestones"},
|
||||
//{"PATCH", "/repos/:owner/:repo/milestones/:number"},
|
||||
{"DELETE", "/repos/:owner/:repo/milestones/:number"},
|
||||
|
||||
// Miscellaneous
|
||||
{"GET", "/emojis"},
|
||||
{"GET", "/gitignore/templates"},
|
||||
{"GET", "/gitignore/templates/:name"},
|
||||
{"POST", "/markdown"},
|
||||
{"POST", "/markdown/raw"},
|
||||
{"GET", "/meta"},
|
||||
{"GET", "/rate_limit"},
|
||||
|
||||
// Organizations
|
||||
{"GET", "/users/:user/orgs"},
|
||||
{"GET", "/user/orgs"},
|
||||
{"GET", "/orgs/:org"},
|
||||
//{"PATCH", "/orgs/:org"},
|
||||
{"GET", "/orgs/:org/members"},
|
||||
{"GET", "/orgs/:org/members/:user"},
|
||||
{"DELETE", "/orgs/:org/members/:user"},
|
||||
{"GET", "/orgs/:org/public_members"},
|
||||
{"GET", "/orgs/:org/public_members/:user"},
|
||||
{"PUT", "/orgs/:org/public_members/:user"},
|
||||
{"DELETE", "/orgs/:org/public_members/:user"},
|
||||
{"GET", "/orgs/:org/teams"},
|
||||
{"GET", "/teams/:id"},
|
||||
{"POST", "/orgs/:org/teams"},
|
||||
//{"PATCH", "/teams/:id"},
|
||||
{"DELETE", "/teams/:id"},
|
||||
{"GET", "/teams/:id/members"},
|
||||
{"GET", "/teams/:id/members/:user"},
|
||||
{"PUT", "/teams/:id/members/:user"},
|
||||
{"DELETE", "/teams/:id/members/:user"},
|
||||
{"GET", "/teams/:id/repos"},
|
||||
{"GET", "/teams/:id/repos/:owner/:repo"},
|
||||
{"PUT", "/teams/:id/repos/:owner/:repo"},
|
||||
{"DELETE", "/teams/:id/repos/:owner/:repo"},
|
||||
{"GET", "/user/teams"},
|
||||
|
||||
// Pull Requests
|
||||
{"GET", "/repos/:owner/:repo/pulls"},
|
||||
{"GET", "/repos/:owner/:repo/pulls/:number"},
|
||||
{"POST", "/repos/:owner/:repo/pulls"},
|
||||
//{"PATCH", "/repos/:owner/:repo/pulls/:number"},
|
||||
{"GET", "/repos/:owner/:repo/pulls/:number/commits"},
|
||||
{"GET", "/repos/:owner/:repo/pulls/:number/files"},
|
||||
{"GET", "/repos/:owner/:repo/pulls/:number/merge"},
|
||||
{"PUT", "/repos/:owner/:repo/pulls/:number/merge"},
|
||||
{"GET", "/repos/:owner/:repo/pulls/:number/comments"},
|
||||
//{"GET", "/repos/:owner/:repo/pulls/comments"},
|
||||
//{"GET", "/repos/:owner/:repo/pulls/comments/:number"},
|
||||
{"PUT", "/repos/:owner/:repo/pulls/:number/comments"},
|
||||
//{"PATCH", "/repos/:owner/:repo/pulls/comments/:number"},
|
||||
//{"DELETE", "/repos/:owner/:repo/pulls/comments/:number"},
|
||||
|
||||
// Repositories
|
||||
{"GET", "/user/repos"},
|
||||
{"GET", "/users/:user/repos"},
|
||||
{"GET", "/orgs/:org/repos"},
|
||||
{"GET", "/repositories"},
|
||||
{"POST", "/user/repos"},
|
||||
{"POST", "/orgs/:org/repos"},
|
||||
{"GET", "/repos/:owner/:repo"},
|
||||
//{"PATCH", "/repos/:owner/:repo"},
|
||||
{"GET", "/repos/:owner/:repo/contributors"},
|
||||
{"GET", "/repos/:owner/:repo/languages"},
|
||||
{"GET", "/repos/:owner/:repo/teams"},
|
||||
{"GET", "/repos/:owner/:repo/tags"},
|
||||
{"GET", "/repos/:owner/:repo/branches"},
|
||||
{"GET", "/repos/:owner/:repo/branches/:branch"},
|
||||
{"DELETE", "/repos/:owner/:repo"},
|
||||
{"GET", "/repos/:owner/:repo/collaborators"},
|
||||
{"GET", "/repos/:owner/:repo/collaborators/:user"},
|
||||
{"PUT", "/repos/:owner/:repo/collaborators/:user"},
|
||||
{"DELETE", "/repos/:owner/:repo/collaborators/:user"},
|
||||
{"GET", "/repos/:owner/:repo/comments"},
|
||||
{"GET", "/repos/:owner/:repo/commits/:sha/comments"},
|
||||
{"POST", "/repos/:owner/:repo/commits/:sha/comments"},
|
||||
{"GET", "/repos/:owner/:repo/comments/:id"},
|
||||
//{"PATCH", "/repos/:owner/:repo/comments/:id"},
|
||||
{"DELETE", "/repos/:owner/:repo/comments/:id"},
|
||||
{"GET", "/repos/:owner/:repo/commits"},
|
||||
{"GET", "/repos/:owner/:repo/commits/:sha"},
|
||||
{"GET", "/repos/:owner/:repo/readme"},
|
||||
//{"GET", "/repos/:owner/:repo/contents/*path"},
|
||||
//{"PUT", "/repos/:owner/:repo/contents/*path"},
|
||||
//{"DELETE", "/repos/:owner/:repo/contents/*path"},
|
||||
//{"GET", "/repos/:owner/:repo/:archive_format/:ref"},
|
||||
{"GET", "/repos/:owner/:repo/keys"},
|
||||
{"GET", "/repos/:owner/:repo/keys/:id"},
|
||||
{"POST", "/repos/:owner/:repo/keys"},
|
||||
//{"PATCH", "/repos/:owner/:repo/keys/:id"},
|
||||
{"DELETE", "/repos/:owner/:repo/keys/:id"},
|
||||
{"GET", "/repos/:owner/:repo/downloads"},
|
||||
{"GET", "/repos/:owner/:repo/downloads/:id"},
|
||||
{"DELETE", "/repos/:owner/:repo/downloads/:id"},
|
||||
{"GET", "/repos/:owner/:repo/forks"},
|
||||
{"POST", "/repos/:owner/:repo/forks"},
|
||||
{"GET", "/repos/:owner/:repo/hooks"},
|
||||
{"GET", "/repos/:owner/:repo/hooks/:id"},
|
||||
{"POST", "/repos/:owner/:repo/hooks"},
|
||||
//{"PATCH", "/repos/:owner/:repo/hooks/:id"},
|
||||
{"POST", "/repos/:owner/:repo/hooks/:id/tests"},
|
||||
{"DELETE", "/repos/:owner/:repo/hooks/:id"},
|
||||
{"POST", "/repos/:owner/:repo/merges"},
|
||||
{"GET", "/repos/:owner/:repo/releases"},
|
||||
{"GET", "/repos/:owner/:repo/releases/:id"},
|
||||
{"POST", "/repos/:owner/:repo/releases"},
|
||||
//{"PATCH", "/repos/:owner/:repo/releases/:id"},
|
||||
{"DELETE", "/repos/:owner/:repo/releases/:id"},
|
||||
{"GET", "/repos/:owner/:repo/releases/:id/assets"},
|
||||
{"GET", "/repos/:owner/:repo/stats/contributors"},
|
||||
{"GET", "/repos/:owner/:repo/stats/commit_activity"},
|
||||
{"GET", "/repos/:owner/:repo/stats/code_frequency"},
|
||||
{"GET", "/repos/:owner/:repo/stats/participation"},
|
||||
{"GET", "/repos/:owner/:repo/stats/punch_card"},
|
||||
{"GET", "/repos/:owner/:repo/statuses/:ref"},
|
||||
{"POST", "/repos/:owner/:repo/statuses/:ref"},
|
||||
|
||||
// Search
|
||||
{"GET", "/search/repositories"},
|
||||
{"GET", "/search/code"},
|
||||
{"GET", "/search/issues"},
|
||||
{"GET", "/search/users"},
|
||||
{"GET", "/legacy/issues/search/:owner/:repository/:state/:keyword"},
|
||||
{"GET", "/legacy/repos/search/:keyword"},
|
||||
{"GET", "/legacy/user/search/:keyword"},
|
||||
{"GET", "/legacy/user/email/:email"},
|
||||
|
||||
// Users
|
||||
{"GET", "/users/:user"},
|
||||
{"GET", "/user"},
|
||||
//{"PATCH", "/user"},
|
||||
{"GET", "/users"},
|
||||
{"GET", "/user/emails"},
|
||||
{"POST", "/user/emails"},
|
||||
{"DELETE", "/user/emails"},
|
||||
{"GET", "/users/:user/followers"},
|
||||
{"GET", "/user/followers"},
|
||||
{"GET", "/users/:user/following"},
|
||||
{"GET", "/user/following"},
|
||||
{"GET", "/user/following/:user"},
|
||||
{"GET", "/users/:user/following/:target_user"},
|
||||
{"PUT", "/user/following/:user"},
|
||||
{"DELETE", "/user/following/:user"},
|
||||
{"GET", "/users/:user/keys"},
|
||||
{"GET", "/user/keys"},
|
||||
{"GET", "/user/keys/:id"},
|
||||
{"POST", "/user/keys"},
|
||||
//{"PATCH", "/user/keys/:id"},
|
||||
{"DELETE", "/user/keys/:id"},
|
||||
}
|
||||
|
||||
func TestGithubAPI(t *testing.T) {
|
||||
router := New()
|
||||
|
||||
for _, route := range githubAPI {
|
||||
router.Handle(route.method, route.path, []HandlerFunc{func(c *Context) {
|
||||
output := H{"status": "good"}
|
||||
for _, param := range c.Params {
|
||||
output[param.Key] = param.Value
|
||||
}
|
||||
c.JSON(200, output)
|
||||
}})
|
||||
}
|
||||
|
||||
for _, route := range githubAPI {
|
||||
path, values := exampleFromPath(route.path)
|
||||
w := performRequest(router, route.method, path)
|
||||
|
||||
// TEST
|
||||
assert.Contains(t, w.Body.String(), "\"status\":\"good\"")
|
||||
for _, value := range values {
|
||||
str := fmt.Sprintf("\"%s\":\"%s\"", value.Key, value.Value)
|
||||
assert.Contains(t, w.Body.String(), str)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func exampleFromPath(path string) (string, Params) {
|
||||
output := new(bytes.Buffer)
|
||||
params := make(Params, 0, 6)
|
||||
start := -1
|
||||
for i, c := range path {
|
||||
if c == ':' {
|
||||
start = i + 1
|
||||
}
|
||||
if start >= 0 {
|
||||
if c == '/' {
|
||||
value := fmt.Sprint(rand.Intn(100000))
|
||||
params = append(params, Param{
|
||||
Key: path[start:i],
|
||||
Value: value,
|
||||
})
|
||||
output.WriteString(value)
|
||||
output.WriteRune(c)
|
||||
start = -1
|
||||
}
|
||||
} else {
|
||||
output.WriteRune(c)
|
||||
}
|
||||
}
|
||||
if start >= 0 {
|
||||
value := fmt.Sprint(rand.Intn(100000))
|
||||
params = append(params, Param{
|
||||
Key: path[start:len(path)],
|
||||
Value: value,
|
||||
})
|
||||
output.WriteString(value)
|
||||
}
|
||||
|
||||
return output.String(), params
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package gin
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
//TODO
|
||||
// func (engine *Engine) LoadHTMLGlob(pattern string) {
|
||||
// func (engine *Engine) LoadHTMLFiles(files ...string) {
|
||||
// func (engine *Engine) Run(addr string) error {
|
||||
// func (engine *Engine) RunTLS(addr string, cert string, key string) error {
|
||||
|
||||
func init() {
|
||||
SetMode(TestMode)
|
||||
}
|
||||
|
||||
func TestLogger(t *testing.T) {
|
||||
buffer := new(bytes.Buffer)
|
||||
router := New()
|
||||
router.Use(LoggerWithFile(buffer))
|
||||
router.GET("/example", func(c *Context) {})
|
||||
|
||||
performRequest(router, "GET", "/example")
|
||||
|
||||
assert.Contains(t, buffer.String(), "200")
|
||||
assert.Contains(t, buffer.String(), "GET")
|
||||
assert.Contains(t, buffer.String(), "/example")
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
// Copyright 2013 Julien Schmidt. All rights reserved.
|
||||
// Based on the path package, Copyright 2009 The Go Authors.
|
||||
// Use of this source code is governed by a BSD-style license that can be found
|
||||
// in the LICENSE file.
|
||||
|
||||
package gin
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var cleanTests = []struct {
|
||||
path, result string
|
||||
}{
|
||||
// Already clean
|
||||
{"/", "/"},
|
||||
{"/abc", "/abc"},
|
||||
{"/a/b/c", "/a/b/c"},
|
||||
{"/abc/", "/abc/"},
|
||||
{"/a/b/c/", "/a/b/c/"},
|
||||
|
||||
// missing root
|
||||
{"", "/"},
|
||||
{"abc", "/abc"},
|
||||
{"abc/def", "/abc/def"},
|
||||
{"a/b/c", "/a/b/c"},
|
||||
|
||||
// Remove doubled slash
|
||||
{"//", "/"},
|
||||
{"/abc//", "/abc/"},
|
||||
{"/abc/def//", "/abc/def/"},
|
||||
{"/a/b/c//", "/a/b/c/"},
|
||||
{"/abc//def//ghi", "/abc/def/ghi"},
|
||||
{"//abc", "/abc"},
|
||||
{"///abc", "/abc"},
|
||||
{"//abc//", "/abc/"},
|
||||
|
||||
// Remove . elements
|
||||
{".", "/"},
|
||||
{"./", "/"},
|
||||
{"/abc/./def", "/abc/def"},
|
||||
{"/./abc/def", "/abc/def"},
|
||||
{"/abc/.", "/abc/"},
|
||||
|
||||
// Remove .. elements
|
||||
{"..", "/"},
|
||||
{"../", "/"},
|
||||
{"../../", "/"},
|
||||
{"../..", "/"},
|
||||
{"../../abc", "/abc"},
|
||||
{"/abc/def/ghi/../jkl", "/abc/def/jkl"},
|
||||
{"/abc/def/../ghi/../jkl", "/abc/jkl"},
|
||||
{"/abc/def/..", "/abc"},
|
||||
{"/abc/def/../..", "/"},
|
||||
{"/abc/def/../../..", "/"},
|
||||
{"/abc/def/../../..", "/"},
|
||||
{"/abc/def/../../../ghi/jkl/../../../mno", "/mno"},
|
||||
|
||||
// Combinations
|
||||
{"abc/./../def", "/def"},
|
||||
{"abc//./../def", "/def"},
|
||||
{"abc/../../././../def", "/def"},
|
||||
}
|
||||
|
||||
func TestPathClean(t *testing.T) {
|
||||
for _, test := range cleanTests {
|
||||
assert.Equal(t, CleanPath(test.path), test.result)
|
||||
assert.Equal(t, CleanPath(test.result), test.result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPathCleanMallocs(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping malloc count in short mode")
|
||||
}
|
||||
if runtime.GOMAXPROCS(0) > 1 {
|
||||
t.Log("skipping AllocsPerRun checks; GOMAXPROCS>1")
|
||||
return
|
||||
}
|
||||
|
||||
for _, test := range cleanTests {
|
||||
allocs := testing.AllocsPerRun(100, func() { CleanPath(test.result) })
|
||||
assert.Equal(t, allocs, 0)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package render
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestRenderJSON(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
err := JSON.Render(w, 201, map[string]interface{}{
|
||||
"foo": "bar",
|
||||
})
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, w.Code, 201)
|
||||
assert.Equal(t, w.Body.String(), "{\"foo\":\"bar\"}\n")
|
||||
assert.Equal(t, w.Header().Get("Content-Type"), "application/json; charset=utf-8")
|
||||
}
|
||||
|
||||
func TestRenderIndentedJSON(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
err := IndentedJSON.Render(w, 202, map[string]interface{}{
|
||||
"foo": "bar",
|
||||
"bar": "foo",
|
||||
})
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, w.Code, 202)
|
||||
assert.Equal(t, w.Body.String(), "{\n \"bar\": \"foo\",\n \"foo\": \"bar\"\n}")
|
||||
assert.Equal(t, w.Header().Get("Content-Type"), "application/json; charset=utf-8")
|
||||
}
|
||||
|
||||
func TestRenderPlain(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
err := Plain.Render(w, 400, "hola %s %d", []interface{}{"manu", 2})
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, w.Code, 400)
|
||||
assert.Equal(t, w.Body.String(), "hola manu 2")
|
||||
assert.Equal(t, w.Header().Get("Content-Type"), "text/plain; charset=utf-8")
|
||||
}
|
||||
|
||||
func TestRenderPlainHTML(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
err := HTMLPlain.Render(w, 401, "hola %s %d", []interface{}{"manu", 2})
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, w.Code, 401)
|
||||
assert.Equal(t, w.Body.String(), "hola manu 2")
|
||||
assert.Equal(t, w.Header().Get("Content-Type"), "text/html; charset=utf-8")
|
||||
}
|
||||
|
||||
func TestRenderHTMLTemplate(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
templ := template.Must(template.New("t").Parse(`Hello {{.name}}`))
|
||||
htmlRender := HTMLRender{Template: templ}
|
||||
err := htmlRender.Render(w, 402, "t", map[string]interface{}{
|
||||
"name": "alexandernyquist",
|
||||
})
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, w.Code, 402)
|
||||
assert.Equal(t, w.Body.String(), "Hello alexandernyquist")
|
||||
assert.Equal(t, w.Header().Get("Content-Type"), "text/html; charset=utf-8")
|
||||
}
|
||||
|
||||
func TestRenderJoinStrings(t *testing.T) {
|
||||
assert.Equal(t, joinStrings("a", "BB", "c"), "aBBc")
|
||||
assert.Equal(t, joinStrings("a", "", "c"), "ac")
|
||||
assert.Equal(t, joinStrings("text/html", "; charset=utf-8"), "text/html; charset=utf-8")
|
||||
|
||||
}
|
|
@ -12,6 +12,11 @@ import (
|
|||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// TODO
|
||||
// func (w *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||
// func (w *responseWriter) CloseNotify() <-chan bool {
|
||||
// func (w *responseWriter) Flush() {
|
||||
|
||||
var _ ResponseWriter = &responseWriter{}
|
||||
var _ http.ResponseWriter = &responseWriter{}
|
||||
var _ http.ResponseWriter = ResponseWriter(&responseWriter{})
|
||||
|
|
|
@ -119,9 +119,10 @@ func (group *RouterGroup) createStaticHandler(absolutePath, root string) func(*C
|
|||
|
||||
func (group *RouterGroup) combineHandlers(handlers []HandlerFunc) []HandlerFunc {
|
||||
finalSize := len(group.Handlers) + len(handlers)
|
||||
mergedHandlers := make([]HandlerFunc, 0, finalSize)
|
||||
mergedHandlers = append(mergedHandlers, group.Handlers...)
|
||||
return append(mergedHandlers, handlers...)
|
||||
mergedHandlers := make([]HandlerFunc, finalSize)
|
||||
copy(mergedHandlers, group.Handlers)
|
||||
copy(mergedHandlers[len(group.Handlers):], handlers)
|
||||
return mergedHandlers
|
||||
}
|
||||
|
||||
func (group *RouterGroup) calculateAbsolutePath(relativePath string) string {
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package gin
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func init() {
|
||||
SetMode(TestMode)
|
||||
}
|
||||
|
||||
func TestRouterGroupBasic(t *testing.T) {
|
||||
router := New()
|
||||
group := router.Group("/hola", func(c *Context) {})
|
||||
group.Use(func(c *Context) {})
|
||||
|
||||
assert.Len(t, group.Handlers, 2)
|
||||
assert.Equal(t, group.absolutePath, "/hola")
|
||||
assert.Equal(t, group.engine, router)
|
||||
|
||||
group2 := group.Group("manu")
|
||||
group2.Use(func(c *Context) {}, func(c *Context) {})
|
||||
|
||||
assert.Len(t, group2.Handlers, 4)
|
||||
assert.Equal(t, group2.absolutePath, "/hola/manu")
|
||||
assert.Equal(t, group2.engine, router)
|
||||
}
|
||||
|
||||
func TestRouterGroupBasicHandle(t *testing.T) {
|
||||
performRequestInGroup(t, "GET")
|
||||
performRequestInGroup(t, "POST")
|
||||
performRequestInGroup(t, "PUT")
|
||||
performRequestInGroup(t, "PATCH")
|
||||
performRequestInGroup(t, "DELETE")
|
||||
performRequestInGroup(t, "HEAD")
|
||||
performRequestInGroup(t, "OPTIONS")
|
||||
performRequestInGroup(t, "LINK")
|
||||
performRequestInGroup(t, "UNLINK")
|
||||
|
||||
}
|
||||
|
||||
func performRequestInGroup(t *testing.T, method string) {
|
||||
router := New()
|
||||
v1 := router.Group("v1", func(c *Context) {})
|
||||
assert.Equal(t, v1.absolutePath, "/v1")
|
||||
|
||||
login := v1.Group("/login/", func(c *Context) {}, func(c *Context) {})
|
||||
assert.Equal(t, login.absolutePath, "/v1/login/")
|
||||
|
||||
handler := func(c *Context) {
|
||||
c.String(400, "the method was %s and index %d", c.Request.Method, c.index)
|
||||
}
|
||||
|
||||
switch method {
|
||||
case "GET":
|
||||
v1.GET("/test", handler)
|
||||
login.GET("/test", handler)
|
||||
case "POST":
|
||||
v1.POST("/test", handler)
|
||||
login.POST("/test", handler)
|
||||
case "PUT":
|
||||
v1.PUT("/test", handler)
|
||||
login.PUT("/test", handler)
|
||||
case "PATCH":
|
||||
v1.PATCH("/test", handler)
|
||||
login.PATCH("/test", handler)
|
||||
case "DELETE":
|
||||
v1.DELETE("/test", handler)
|
||||
login.DELETE("/test", handler)
|
||||
case "HEAD":
|
||||
v1.HEAD("/test", handler)
|
||||
login.HEAD("/test", handler)
|
||||
case "OPTIONS":
|
||||
v1.OPTIONS("/test", handler)
|
||||
login.OPTIONS("/test", handler)
|
||||
case "LINK":
|
||||
v1.LINK("/test", handler)
|
||||
login.LINK("/test", handler)
|
||||
case "UNLINK":
|
||||
v1.UNLINK("/test", handler)
|
||||
login.UNLINK("/test", handler)
|
||||
default:
|
||||
panic("unknown method")
|
||||
}
|
||||
|
||||
w := performRequest(router, method, "/v1/login/test")
|
||||
assert.Equal(t, w.Code, 400)
|
||||
assert.Equal(t, w.Body.String(), "the method was "+method+" and index 3")
|
||||
|
||||
w = performRequest(router, method, "/v1/test")
|
||||
assert.Equal(t, w.Code, 400)
|
||||
assert.Equal(t, w.Body.String(), "the method was "+method+" and index 1")
|
||||
}
|
|
@ -0,0 +1,608 @@
|
|||
// Copyright 2013 Julien Schmidt. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be found
|
||||
// in the LICENSE file.
|
||||
|
||||
package gin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func printChildren(n *node, prefix string) {
|
||||
fmt.Printf(" %02d:%02d %s%s[%d] %v %t %d \r\n", n.priority, n.maxParams, prefix, n.path, len(n.children), n.handlers, n.wildChild, n.nType)
|
||||
for l := len(n.path); l > 0; l-- {
|
||||
prefix += " "
|
||||
}
|
||||
for _, child := range n.children {
|
||||
printChildren(child, prefix)
|
||||
}
|
||||
}
|
||||
|
||||
// Used as a workaround since we can't compare functions or their adresses
|
||||
var fakeHandlerValue string
|
||||
|
||||
func fakeHandler(val string) []HandlerFunc {
|
||||
return []HandlerFunc{func(c *Context) {
|
||||
fakeHandlerValue = val
|
||||
}}
|
||||
}
|
||||
|
||||
type testRequests []struct {
|
||||
path string
|
||||
nilHandler bool
|
||||
route string
|
||||
ps Params
|
||||
}
|
||||
|
||||
func checkRequests(t *testing.T, tree *node, requests testRequests) {
|
||||
for _, request := range requests {
|
||||
handler, ps, _ := tree.getValue(request.path, nil)
|
||||
|
||||
if handler == nil {
|
||||
if !request.nilHandler {
|
||||
t.Errorf("handle mismatch for route '%s': Expected non-nil handle", request.path)
|
||||
}
|
||||
} else if request.nilHandler {
|
||||
t.Errorf("handle mismatch for route '%s': Expected nil handle", request.path)
|
||||
} else {
|
||||
handler[0](nil)
|
||||
if fakeHandlerValue != request.route {
|
||||
t.Errorf("handle mismatch for route '%s': Wrong handle (%s != %s)", request.path, fakeHandlerValue, request.route)
|
||||
}
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(ps, request.ps) {
|
||||
t.Errorf("Params mismatch for route '%s'", request.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func checkPriorities(t *testing.T, n *node) uint32 {
|
||||
var prio uint32
|
||||
for i := range n.children {
|
||||
prio += checkPriorities(t, n.children[i])
|
||||
}
|
||||
|
||||
if n.handlers != nil {
|
||||
prio++
|
||||
}
|
||||
|
||||
if n.priority != prio {
|
||||
t.Errorf(
|
||||
"priority mismatch for node '%s': is %d, should be %d",
|
||||
n.path, n.priority, prio,
|
||||
)
|
||||
}
|
||||
|
||||
return prio
|
||||
}
|
||||
|
||||
func checkMaxParams(t *testing.T, n *node) uint8 {
|
||||
var maxParams uint8
|
||||
for i := range n.children {
|
||||
params := checkMaxParams(t, n.children[i])
|
||||
if params > maxParams {
|
||||
maxParams = params
|
||||
}
|
||||
}
|
||||
if n.nType != static && !n.wildChild {
|
||||
maxParams++
|
||||
}
|
||||
|
||||
if n.maxParams != maxParams {
|
||||
t.Errorf(
|
||||
"maxParams mismatch for node '%s': is %d, should be %d",
|
||||
n.path, n.maxParams, maxParams,
|
||||
)
|
||||
}
|
||||
|
||||
return maxParams
|
||||
}
|
||||
|
||||
func TestCountParams(t *testing.T) {
|
||||
if countParams("/path/:param1/static/*catch-all") != 2 {
|
||||
t.Fail()
|
||||
}
|
||||
if countParams(strings.Repeat("/:param", 256)) != 255 {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestTreeAddAndGet(t *testing.T) {
|
||||
tree := &node{}
|
||||
|
||||
routes := [...]string{
|
||||
"/hi",
|
||||
"/contact",
|
||||
"/co",
|
||||
"/c",
|
||||
"/a",
|
||||
"/ab",
|
||||
"/doc/",
|
||||
"/doc/go_faq.html",
|
||||
"/doc/go1.html",
|
||||
"/α",
|
||||
"/β",
|
||||
}
|
||||
for _, route := range routes {
|
||||
tree.addRoute(route, fakeHandler(route))
|
||||
}
|
||||
|
||||
//printChildren(tree, "")
|
||||
|
||||
checkRequests(t, tree, testRequests{
|
||||
{"/a", false, "/a", nil},
|
||||
{"/", true, "", nil},
|
||||
{"/hi", false, "/hi", nil},
|
||||
{"/contact", false, "/contact", nil},
|
||||
{"/co", false, "/co", nil},
|
||||
{"/con", true, "", nil}, // key mismatch
|
||||
{"/cona", true, "", nil}, // key mismatch
|
||||
{"/no", true, "", nil}, // no matching child
|
||||
{"/ab", false, "/ab", nil},
|
||||
{"/α", false, "/α", nil},
|
||||
{"/β", false, "/β", nil},
|
||||
})
|
||||
|
||||
checkPriorities(t, tree)
|
||||
checkMaxParams(t, tree)
|
||||
}
|
||||
|
||||
func TestTreeWildcard(t *testing.T) {
|
||||
tree := &node{}
|
||||
|
||||
routes := [...]string{
|
||||
"/",
|
||||
"/cmd/:tool/:sub",
|
||||
"/cmd/:tool/",
|
||||
"/src/*filepath",
|
||||
"/search/",
|
||||
"/search/:query",
|
||||
"/user_:name",
|
||||
"/user_:name/about",
|
||||
"/files/:dir/*filepath",
|
||||
"/doc/",
|
||||
"/doc/go_faq.html",
|
||||
"/doc/go1.html",
|
||||
"/info/:user/public",
|
||||
"/info/:user/project/:project",
|
||||
}
|
||||
for _, route := range routes {
|
||||
tree.addRoute(route, fakeHandler(route))
|
||||
}
|
||||
|
||||
//printChildren(tree, "")
|
||||
|
||||
checkRequests(t, tree, testRequests{
|
||||
{"/", false, "/", nil},
|
||||
{"/cmd/test/", false, "/cmd/:tool/", Params{Param{"tool", "test"}}},
|
||||
{"/cmd/test", true, "", Params{Param{"tool", "test"}}},
|
||||
{"/cmd/test/3", false, "/cmd/:tool/:sub", Params{Param{"tool", "test"}, Param{"sub", "3"}}},
|
||||
{"/src/", false, "/src/*filepath", Params{Param{"filepath", "/"}}},
|
||||
{"/src/some/file.png", false, "/src/*filepath", Params{Param{"filepath", "/some/file.png"}}},
|
||||
{"/search/", false, "/search/", nil},
|
||||
{"/search/someth!ng+in+ünìcodé", false, "/search/:query", Params{Param{"query", "someth!ng+in+ünìcodé"}}},
|
||||
{"/search/someth!ng+in+ünìcodé/", true, "", Params{Param{"query", "someth!ng+in+ünìcodé"}}},
|
||||
{"/user_gopher", false, "/user_:name", Params{Param{"name", "gopher"}}},
|
||||
{"/user_gopher/about", false, "/user_:name/about", Params{Param{"name", "gopher"}}},
|
||||
{"/files/js/inc/framework.js", false, "/files/:dir/*filepath", Params{Param{"dir", "js"}, Param{"filepath", "/inc/framework.js"}}},
|
||||
{"/info/gordon/public", false, "/info/:user/public", Params{Param{"user", "gordon"}}},
|
||||
{"/info/gordon/project/go", false, "/info/:user/project/:project", Params{Param{"user", "gordon"}, Param{"project", "go"}}},
|
||||
})
|
||||
|
||||
checkPriorities(t, tree)
|
||||
checkMaxParams(t, tree)
|
||||
}
|
||||
|
||||
func catchPanic(testFunc func()) (recv interface{}) {
|
||||
defer func() {
|
||||
recv = recover()
|
||||
}()
|
||||
|
||||
testFunc()
|
||||
return
|
||||
}
|
||||
|
||||
type testRoute struct {
|
||||
path string
|
||||
conflict bool
|
||||
}
|
||||
|
||||
func testRoutes(t *testing.T, routes []testRoute) {
|
||||
tree := &node{}
|
||||
|
||||
for _, route := range routes {
|
||||
recv := catchPanic(func() {
|
||||
tree.addRoute(route.path, nil)
|
||||
})
|
||||
|
||||
if route.conflict {
|
||||
if recv == nil {
|
||||
t.Errorf("no panic for conflicting route '%s'", route.path)
|
||||
}
|
||||
} else if recv != nil {
|
||||
t.Errorf("unexpected panic for route '%s': %v", route.path, recv)
|
||||
}
|
||||
}
|
||||
|
||||
//printChildren(tree, "")
|
||||
}
|
||||
|
||||
func TestTreeWildcardConflict(t *testing.T) {
|
||||
routes := []testRoute{
|
||||
{"/cmd/:tool/:sub", false},
|
||||
{"/cmd/vet", true},
|
||||
{"/src/*filepath", false},
|
||||
{"/src/*filepathx", true},
|
||||
{"/src/", true},
|
||||
{"/src1/", false},
|
||||
{"/src1/*filepath", true},
|
||||
{"/src2*filepath", true},
|
||||
{"/search/:query", false},
|
||||
{"/search/invalid", true},
|
||||
{"/user_:name", false},
|
||||
{"/user_x", true},
|
||||
{"/user_:name", false},
|
||||
{"/id:id", false},
|
||||
{"/id/:id", true},
|
||||
}
|
||||
testRoutes(t, routes)
|
||||
}
|
||||
|
||||
func TestTreeChildConflict(t *testing.T) {
|
||||
routes := []testRoute{
|
||||
{"/cmd/vet", false},
|
||||
{"/cmd/:tool/:sub", true},
|
||||
{"/src/AUTHORS", false},
|
||||
{"/src/*filepath", true},
|
||||
{"/user_x", false},
|
||||
{"/user_:name", true},
|
||||
{"/id/:id", false},
|
||||
{"/id:id", true},
|
||||
{"/:id", true},
|
||||
{"/*filepath", true},
|
||||
}
|
||||
testRoutes(t, routes)
|
||||
}
|
||||
|
||||
func TestTreeDupliatePath(t *testing.T) {
|
||||
tree := &node{}
|
||||
|
||||
routes := [...]string{
|
||||
"/",
|
||||
"/doc/",
|
||||
"/src/*filepath",
|
||||
"/search/:query",
|
||||
"/user_:name",
|
||||
}
|
||||
for _, route := range routes {
|
||||
recv := catchPanic(func() {
|
||||
tree.addRoute(route, fakeHandler(route))
|
||||
})
|
||||
if recv != nil {
|
||||
t.Fatalf("panic inserting route '%s': %v", route, recv)
|
||||
}
|
||||
|
||||
// Add again
|
||||
recv = catchPanic(func() {
|
||||
tree.addRoute(route, nil)
|
||||
})
|
||||
if recv == nil {
|
||||
t.Fatalf("no panic while inserting duplicate route '%s", route)
|
||||
}
|
||||
}
|
||||
|
||||
//printChildren(tree, "")
|
||||
|
||||
checkRequests(t, tree, testRequests{
|
||||
{"/", false, "/", nil},
|
||||
{"/doc/", false, "/doc/", nil},
|
||||
{"/src/some/file.png", false, "/src/*filepath", Params{Param{"filepath", "/some/file.png"}}},
|
||||
{"/search/someth!ng+in+ünìcodé", false, "/search/:query", Params{Param{"query", "someth!ng+in+ünìcodé"}}},
|
||||
{"/user_gopher", false, "/user_:name", Params{Param{"name", "gopher"}}},
|
||||
})
|
||||
}
|
||||
|
||||
func TestEmptyWildcardName(t *testing.T) {
|
||||
tree := &node{}
|
||||
|
||||
routes := [...]string{
|
||||
"/user:",
|
||||
"/user:/",
|
||||
"/cmd/:/",
|
||||
"/src/*",
|
||||
}
|
||||
for _, route := range routes {
|
||||
recv := catchPanic(func() {
|
||||
tree.addRoute(route, nil)
|
||||
})
|
||||
if recv == nil {
|
||||
t.Fatalf("no panic while inserting route with empty wildcard name '%s", route)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTreeCatchAllConflict(t *testing.T) {
|
||||
routes := []testRoute{
|
||||
{"/src/*filepath/x", true},
|
||||
{"/src2/", false},
|
||||
{"/src2/*filepath/x", true},
|
||||
}
|
||||
testRoutes(t, routes)
|
||||
}
|
||||
|
||||
func TestTreeCatchAllConflictRoot(t *testing.T) {
|
||||
routes := []testRoute{
|
||||
{"/", false},
|
||||
{"/*filepath", true},
|
||||
}
|
||||
testRoutes(t, routes)
|
||||
}
|
||||
|
||||
func TestTreeDoubleWildcard(t *testing.T) {
|
||||
const panicMsg = "only one wildcard per path segment is allowed"
|
||||
|
||||
routes := [...]string{
|
||||
"/:foo:bar",
|
||||
"/:foo:bar/",
|
||||
"/:foo*bar",
|
||||
}
|
||||
|
||||
for _, route := range routes {
|
||||
tree := &node{}
|
||||
recv := catchPanic(func() {
|
||||
tree.addRoute(route, nil)
|
||||
})
|
||||
|
||||
if rs, ok := recv.(string); !ok || rs != panicMsg {
|
||||
t.Fatalf(`"Expected panic "%s" for route '%s', got "%v"`, panicMsg, route, recv)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*func TestTreeDuplicateWildcard(t *testing.T) {
|
||||
tree := &node{}
|
||||
|
||||
routes := [...]string{
|
||||
"/:id/:name/:id",
|
||||
}
|
||||
for _, route := range routes {
|
||||
...
|
||||
}
|
||||
}*/
|
||||
|
||||
func TestTreeTrailingSlashRedirect(t *testing.T) {
|
||||
tree := &node{}
|
||||
|
||||
routes := [...]string{
|
||||
"/hi",
|
||||
"/b/",
|
||||
"/search/:query",
|
||||
"/cmd/:tool/",
|
||||
"/src/*filepath",
|
||||
"/x",
|
||||
"/x/y",
|
||||
"/y/",
|
||||
"/y/z",
|
||||
"/0/:id",
|
||||
"/0/:id/1",
|
||||
"/1/:id/",
|
||||
"/1/:id/2",
|
||||
"/aa",
|
||||
"/a/",
|
||||
"/doc",
|
||||
"/doc/go_faq.html",
|
||||
"/doc/go1.html",
|
||||
"/no/a",
|
||||
"/no/b",
|
||||
"/api/hello/:name",
|
||||
}
|
||||
for _, route := range routes {
|
||||
recv := catchPanic(func() {
|
||||
tree.addRoute(route, fakeHandler(route))
|
||||
})
|
||||
if recv != nil {
|
||||
t.Fatalf("panic inserting route '%s': %v", route, recv)
|
||||
}
|
||||
}
|
||||
|
||||
//printChildren(tree, "")
|
||||
|
||||
tsrRoutes := [...]string{
|
||||
"/hi/",
|
||||
"/b",
|
||||
"/search/gopher/",
|
||||
"/cmd/vet",
|
||||
"/src",
|
||||
"/x/",
|
||||
"/y",
|
||||
"/0/go/",
|
||||
"/1/go",
|
||||
"/a",
|
||||
"/doc/",
|
||||
}
|
||||
for _, route := range tsrRoutes {
|
||||
handler, _, tsr := tree.getValue(route, nil)
|
||||
if handler != nil {
|
||||
t.Fatalf("non-nil handler for TSR route '%s", route)
|
||||
} else if !tsr {
|
||||
t.Errorf("expected TSR recommendation for route '%s'", route)
|
||||
}
|
||||
}
|
||||
|
||||
noTsrRoutes := [...]string{
|
||||
"/",
|
||||
"/no",
|
||||
"/no/",
|
||||
"/_",
|
||||
"/_/",
|
||||
"/api/world/abc",
|
||||
}
|
||||
for _, route := range noTsrRoutes {
|
||||
handler, _, tsr := tree.getValue(route, nil)
|
||||
if handler != nil {
|
||||
t.Fatalf("non-nil handler for No-TSR route '%s", route)
|
||||
} else if tsr {
|
||||
t.Errorf("expected no TSR recommendation for route '%s'", route)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTreeFindCaseInsensitivePath(t *testing.T) {
|
||||
tree := &node{}
|
||||
|
||||
routes := [...]string{
|
||||
"/hi",
|
||||
"/b/",
|
||||
"/ABC/",
|
||||
"/search/:query",
|
||||
"/cmd/:tool/",
|
||||
"/src/*filepath",
|
||||
"/x",
|
||||
"/x/y",
|
||||
"/y/",
|
||||
"/y/z",
|
||||
"/0/:id",
|
||||
"/0/:id/1",
|
||||
"/1/:id/",
|
||||
"/1/:id/2",
|
||||
"/aa",
|
||||
"/a/",
|
||||
"/doc",
|
||||
"/doc/go_faq.html",
|
||||
"/doc/go1.html",
|
||||
"/doc/go/away",
|
||||
"/no/a",
|
||||
"/no/b",
|
||||
}
|
||||
|
||||
for _, route := range routes {
|
||||
recv := catchPanic(func() {
|
||||
tree.addRoute(route, fakeHandler(route))
|
||||
})
|
||||
if recv != nil {
|
||||
t.Fatalf("panic inserting route '%s': %v", route, recv)
|
||||
}
|
||||
}
|
||||
|
||||
// Check out == in for all registered routes
|
||||
// With fixTrailingSlash = true
|
||||
for _, route := range routes {
|
||||
out, found := tree.findCaseInsensitivePath(route, true)
|
||||
if !found {
|
||||
t.Errorf("Route '%s' not found!", route)
|
||||
} else if string(out) != route {
|
||||
t.Errorf("Wrong result for route '%s': %s", route, string(out))
|
||||
}
|
||||
}
|
||||
// With fixTrailingSlash = false
|
||||
for _, route := range routes {
|
||||
out, found := tree.findCaseInsensitivePath(route, false)
|
||||
if !found {
|
||||
t.Errorf("Route '%s' not found!", route)
|
||||
} else if string(out) != route {
|
||||
t.Errorf("Wrong result for route '%s': %s", route, string(out))
|
||||
}
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
in string
|
||||
out string
|
||||
found bool
|
||||
slash bool
|
||||
}{
|
||||
{"/HI", "/hi", true, false},
|
||||
{"/HI/", "/hi", true, true},
|
||||
{"/B", "/b/", true, true},
|
||||
{"/B/", "/b/", true, false},
|
||||
{"/abc", "/ABC/", true, true},
|
||||
{"/abc/", "/ABC/", true, false},
|
||||
{"/aBc", "/ABC/", true, true},
|
||||
{"/aBc/", "/ABC/", true, false},
|
||||
{"/abC", "/ABC/", true, true},
|
||||
{"/abC/", "/ABC/", true, false},
|
||||
{"/SEARCH/QUERY", "/search/QUERY", true, false},
|
||||
{"/SEARCH/QUERY/", "/search/QUERY", true, true},
|
||||
{"/CMD/TOOL/", "/cmd/TOOL/", true, false},
|
||||
{"/CMD/TOOL", "/cmd/TOOL/", true, true},
|
||||
{"/SRC/FILE/PATH", "/src/FILE/PATH", true, false},
|
||||
{"/x/Y", "/x/y", true, false},
|
||||
{"/x/Y/", "/x/y", true, true},
|
||||
{"/X/y", "/x/y", true, false},
|
||||
{"/X/y/", "/x/y", true, true},
|
||||
{"/X/Y", "/x/y", true, false},
|
||||
{"/X/Y/", "/x/y", true, true},
|
||||
{"/Y/", "/y/", true, false},
|
||||
{"/Y", "/y/", true, true},
|
||||
{"/Y/z", "/y/z", true, false},
|
||||
{"/Y/z/", "/y/z", true, true},
|
||||
{"/Y/Z", "/y/z", true, false},
|
||||
{"/Y/Z/", "/y/z", true, true},
|
||||
{"/y/Z", "/y/z", true, false},
|
||||
{"/y/Z/", "/y/z", true, true},
|
||||
{"/Aa", "/aa", true, false},
|
||||
{"/Aa/", "/aa", true, true},
|
||||
{"/AA", "/aa", true, false},
|
||||
{"/AA/", "/aa", true, true},
|
||||
{"/aA", "/aa", true, false},
|
||||
{"/aA/", "/aa", true, true},
|
||||
{"/A/", "/a/", true, false},
|
||||
{"/A", "/a/", true, true},
|
||||
{"/DOC", "/doc", true, false},
|
||||
{"/DOC/", "/doc", true, true},
|
||||
{"/NO", "", false, true},
|
||||
{"/DOC/GO", "", false, true},
|
||||
}
|
||||
// With fixTrailingSlash = true
|
||||
for _, test := range tests {
|
||||
out, found := tree.findCaseInsensitivePath(test.in, true)
|
||||
if found != test.found || (found && (string(out) != test.out)) {
|
||||
t.Errorf("Wrong result for '%s': got %s, %t; want %s, %t",
|
||||
test.in, string(out), found, test.out, test.found)
|
||||
return
|
||||
}
|
||||
}
|
||||
// With fixTrailingSlash = false
|
||||
for _, test := range tests {
|
||||
out, found := tree.findCaseInsensitivePath(test.in, false)
|
||||
if test.slash {
|
||||
if found { // test needs a trailingSlash fix. It must not be found!
|
||||
t.Errorf("Found without fixTrailingSlash: %s; got %s", test.in, string(out))
|
||||
}
|
||||
} else {
|
||||
if found != test.found || (found && (string(out) != test.out)) {
|
||||
t.Errorf("Wrong result for '%s': got %s, %t; want %s, %t",
|
||||
test.in, string(out), found, test.out, test.found)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTreeInvalidNodeType(t *testing.T) {
|
||||
tree := &node{}
|
||||
tree.addRoute("/", fakeHandler("/"))
|
||||
tree.addRoute("/:page", fakeHandler("/:page"))
|
||||
|
||||
// set invalid node type
|
||||
tree.children[0].nType = 42
|
||||
|
||||
// normal lookup
|
||||
recv := catchPanic(func() {
|
||||
tree.getValue("/test", nil)
|
||||
})
|
||||
if rs, ok := recv.(string); !ok || rs != "Invalid node type" {
|
||||
t.Fatalf(`Expected panic "Invalid node type", got "%v"`, recv)
|
||||
}
|
||||
|
||||
// case-insensitive lookup
|
||||
recv = catchPanic(func() {
|
||||
tree.findCaseInsensitivePath("/test", true)
|
||||
})
|
||||
if rs, ok := recv.(string); !ok || rs != "Invalid node type" {
|
||||
t.Fatalf(`Expected panic "Invalid node type", got "%v"`, recv)
|
||||
}
|
||||
}
|
|
@ -45,7 +45,17 @@ func TestFilterFlags(t *testing.T) {
|
|||
assert.Equal(t, result, "text/html")
|
||||
}
|
||||
|
||||
func TestFunctionName(t *testing.T) {
|
||||
assert.Equal(t, nameOfFunction(somefunction), "github.com/gin-gonic/gin.somefunction")
|
||||
}
|
||||
|
||||
func somefunction() {
|
||||
|
||||
}
|
||||
|
||||
func TestJoinPaths(t *testing.T) {
|
||||
assert.Equal(t, joinPaths("", ""), "")
|
||||
assert.Equal(t, joinPaths("", "/"), "/")
|
||||
assert.Equal(t, joinPaths("/a", ""), "/a")
|
||||
assert.Equal(t, joinPaths("/a/", ""), "/a/")
|
||||
assert.Equal(t, joinPaths("/a/", "/"), "/a/")
|
||||
|
|
Loading…
Reference in New Issue