mirror of
https://github.com/gin-gonic/gin.git
synced 2025-10-16 13:22:09 +08:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
6d99972647
49
.github/workflows/codeql.yml
vendored
Normal file
49
.github/workflows/codeql.yml
vendored
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
# For most projects, this workflow file will not need changing; you simply need
|
||||||
|
# to commit it to your repository.
|
||||||
|
#
|
||||||
|
# You may wish to alter this file to override the set of languages analyzed,
|
||||||
|
# or to provide custom queries or build logic.
|
||||||
|
name: "CodeQL"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
pull_request:
|
||||||
|
# The branches below must be a subset of the branches above
|
||||||
|
branches: [ master ]
|
||||||
|
schedule:
|
||||||
|
- cron: '0 17 * * 5'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
analyze:
|
||||||
|
name: Analyze
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
# required for all workflows
|
||||||
|
security-events: write
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
# Override automatic language detection by changing the below list
|
||||||
|
# Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
|
||||||
|
# TODO: Enable for javascript later
|
||||||
|
language: [ 'go']
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
# Initializes the CodeQL tools for scanning.
|
||||||
|
- name: Initialize CodeQL
|
||||||
|
uses: github/codeql-action/init@v1
|
||||||
|
with:
|
||||||
|
languages: ${{ matrix.language }}
|
||||||
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
|
# By default, queries listed here will override any specified in a config file.
|
||||||
|
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||||
|
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||||
|
|
||||||
|
- name: Perform CodeQL Analysis
|
||||||
|
uses: github/codeql-action/analyze@v1
|
2
.github/workflows/gin.yml
vendored
2
.github/workflows/gin.yml
vendored
@ -21,7 +21,7 @@ jobs:
|
|||||||
- name: Setup golangci-lint
|
- name: Setup golangci-lint
|
||||||
uses: golangci/golangci-lint-action@v2
|
uses: golangci/golangci-lint-action@v2
|
||||||
with:
|
with:
|
||||||
version: v1.43.0
|
version: v1.44.0
|
||||||
args: --verbose
|
args: --verbose
|
||||||
test:
|
test:
|
||||||
needs: lint
|
needs: lint
|
||||||
|
@ -384,7 +384,7 @@ func main() {
|
|||||||
// Set a lower memory limit for multipart forms (default is 32 MiB)
|
// Set a lower memory limit for multipart forms (default is 32 MiB)
|
||||||
router.MaxMultipartMemory = 8 << 20 // 8 MiB
|
router.MaxMultipartMemory = 8 << 20 // 8 MiB
|
||||||
router.POST("/upload", func(c *gin.Context) {
|
router.POST("/upload", func(c *gin.Context) {
|
||||||
// single file
|
// Single file
|
||||||
file, _ := c.FormFile("Filename")
|
file, _ := c.FormFile("Filename")
|
||||||
log.Println(file.Filename)
|
log.Println(file.Filename)
|
||||||
|
|
||||||
@ -417,7 +417,7 @@ func main() {
|
|||||||
router.POST("/upload", func(c *gin.Context) {
|
router.POST("/upload", func(c *gin.Context) {
|
||||||
// Multipart form
|
// Multipart form
|
||||||
form, _ := c.MultipartForm()
|
form, _ := c.MultipartForm()
|
||||||
files := form.File["upload[]"]
|
files := form.File["Filename[]"]
|
||||||
|
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
log.Println(file.Filename)
|
log.Println(file.Filename)
|
||||||
@ -906,7 +906,7 @@ func startPage(c *gin.Context) {
|
|||||||
var person Person
|
var person Person
|
||||||
// If `GET`, only `Form` binding engine (`query`) used.
|
// If `GET`, only `Form` binding engine (`query`) used.
|
||||||
// If `POST`, first checks the `content-type` for `JSON` or `XML`, then uses `Form` (`form-data`).
|
// If `POST`, first checks the `content-type` for `JSON` or `XML`, then uses `Form` (`form-data`).
|
||||||
// See more at https://github.com/gin-gonic/gin/blob/master/binding/binding.go#L48
|
// See more at https://github.com/gin-gonic/gin/blob/master/binding/binding.go#L88
|
||||||
if c.ShouldBind(&person) == nil {
|
if c.ShouldBind(&person) == nil {
|
||||||
log.Println(person.Name)
|
log.Println(person.Name)
|
||||||
log.Println(person.Address)
|
log.Println(person.Address)
|
||||||
|
@ -40,7 +40,7 @@ type BindingBody interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// BindingUri adds BindUri method to Binding. BindUri is similar with Bind,
|
// BindingUri adds BindUri method to Binding. BindUri is similar with Bind,
|
||||||
// but it read the Params.
|
// but it reads the Params.
|
||||||
type BindingUri interface {
|
type BindingUri interface {
|
||||||
Name() string
|
Name() string
|
||||||
BindUri(map[string][]string, interface{}) error
|
BindUri(map[string][]string, interface{}) error
|
||||||
|
@ -38,7 +38,7 @@ type BindingBody interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// BindingUri adds BindUri method to Binding. BindUri is similar with Bind,
|
// BindingUri adds BindUri method to Binding. BindUri is similar with Bind,
|
||||||
// but it read the Params.
|
// but it reads the Params.
|
||||||
type BindingUri interface {
|
type BindingUri interface {
|
||||||
Name() string
|
Name() string
|
||||||
BindUri(map[string][]string, interface{}) error
|
BindUri(map[string][]string, interface{}) error
|
||||||
|
20
context.go
20
context.go
@ -59,7 +59,7 @@ type Context struct {
|
|||||||
params *Params
|
params *Params
|
||||||
skippedNodes *[]skippedNode
|
skippedNodes *[]skippedNode
|
||||||
|
|
||||||
// This mutex protect Keys map
|
// This mutex protects Keys map.
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
|
|
||||||
// Keys is a key/value pair exclusively for the context of each request.
|
// Keys is a key/value pair exclusively for the context of each request.
|
||||||
@ -71,10 +71,10 @@ type Context struct {
|
|||||||
// Accepted defines a list of manually accepted formats for content negotiation.
|
// Accepted defines a list of manually accepted formats for content negotiation.
|
||||||
Accepted []string
|
Accepted []string
|
||||||
|
|
||||||
// queryCache use url.ParseQuery cached the param query result from c.Request.URL.Query()
|
// queryCache caches the query result from c.Request.URL.Query().
|
||||||
queryCache url.Values
|
queryCache url.Values
|
||||||
|
|
||||||
// formCache use url.ParseQuery cached PostForm contains the parsed form data from POST, PATCH,
|
// formCache caches c.Request.PostForm, which contains the parsed form data from POST, PATCH,
|
||||||
// or PUT body parameters.
|
// or PUT body parameters.
|
||||||
formCache url.Values
|
formCache url.Values
|
||||||
|
|
||||||
@ -601,11 +601,10 @@ func (c *Context) SaveUploadedFile(file *multipart.FileHeader, dst string) error
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bind checks the Content-Type to select a binding engine automatically,
|
// Bind checks the Method and Content-Type to select a binding engine automatically,
|
||||||
// Depending on the "Content-Type" header different bindings are used:
|
// Depending on the "Content-Type" header different bindings are used, for example:
|
||||||
// "application/json" --> JSON binding
|
// "application/json" --> JSON binding
|
||||||
// "application/xml" --> XML binding
|
// "application/xml" --> XML binding
|
||||||
// otherwise --> returns an error.
|
|
||||||
// It parses the request's body as JSON if Content-Type == "application/json" using JSON or XML as a JSON input.
|
// It parses the request's body as JSON if Content-Type == "application/json" using JSON or XML as a JSON input.
|
||||||
// It decodes the json payload into the struct specified as a pointer.
|
// It decodes the json payload into the struct specified as a pointer.
|
||||||
// It writes a 400 error and sets Content-Type header "text/plain" in the response if input is not valid.
|
// It writes a 400 error and sets Content-Type header "text/plain" in the response if input is not valid.
|
||||||
@ -660,14 +659,13 @@ func (c *Context) MustBindWith(obj interface{}, b binding.Binding) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShouldBind checks the Content-Type to select a binding engine automatically,
|
// ShouldBind checks the Method and Content-Type to select a binding engine automatically,
|
||||||
// Depending on the "Content-Type" header different bindings are used:
|
// Depending on the "Content-Type" header different bindings are used, for example:
|
||||||
// "application/json" --> JSON binding
|
// "application/json" --> JSON binding
|
||||||
// "application/xml" --> XML binding
|
// "application/xml" --> XML binding
|
||||||
// otherwise --> returns an error
|
|
||||||
// It parses the request's body as JSON if Content-Type == "application/json" using JSON or XML as a JSON input.
|
// It parses the request's body as JSON if Content-Type == "application/json" using JSON or XML as a JSON input.
|
||||||
// It decodes the json payload into the struct specified as a pointer.
|
// It decodes the json payload into the struct specified as a pointer.
|
||||||
// Like c.Bind() but this method does not set the response status code to 400 and abort if the json is not valid.
|
// Like c.Bind() but this method does not set the response status code to 400 or abort if input is not valid.
|
||||||
func (c *Context) ShouldBind(obj interface{}) error {
|
func (c *Context) ShouldBind(obj interface{}) error {
|
||||||
b := binding.Default(c.Request.Method, c.ContentType())
|
b := binding.Default(c.Request.Method, c.ContentType())
|
||||||
return c.ShouldBindWith(obj, b)
|
return c.ShouldBindWith(obj, b)
|
||||||
@ -843,7 +841,7 @@ func (c *Context) GetHeader(key string) string {
|
|||||||
return c.requestHeader(key)
|
return c.requestHeader(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRawData return stream data.
|
// GetRawData returns stream data.
|
||||||
func (c *Context) GetRawData() ([]byte, error) {
|
func (c *Context) GetRawData() ([]byte, error) {
|
||||||
return ioutil.ReadAll(c.Request.Body)
|
return ioutil.ReadAll(c.Request.Body)
|
||||||
}
|
}
|
||||||
|
@ -2036,8 +2036,8 @@ func TestRaceParamsContextCopy(t *testing.T) {
|
|||||||
}(c.Copy(), c.Param("name"))
|
}(c.Copy(), c.Param("name"))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
performRequest(router, "GET", "/name1/api")
|
PerformRequest(router, "GET", "/name1/api")
|
||||||
performRequest(router, "GET", "/name2/api")
|
PerformRequest(router, "GET", "/name2/api")
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
22
gin.go
22
gin.go
@ -16,6 +16,8 @@ import (
|
|||||||
|
|
||||||
"github.com/gin-gonic/gin/internal/bytesconv"
|
"github.com/gin-gonic/gin/internal/bytesconv"
|
||||||
"github.com/gin-gonic/gin/render"
|
"github.com/gin-gonic/gin/render"
|
||||||
|
"golang.org/x/net/http2"
|
||||||
|
"golang.org/x/net/http2/h2c"
|
||||||
)
|
)
|
||||||
|
|
||||||
const defaultMultipartMemory = 32 << 20 // 32 MB
|
const defaultMultipartMemory = 32 << 20 // 32 MB
|
||||||
@ -141,6 +143,9 @@ type Engine struct {
|
|||||||
// method call.
|
// method call.
|
||||||
MaxMultipartMemory int64
|
MaxMultipartMemory int64
|
||||||
|
|
||||||
|
// Enable h2c support.
|
||||||
|
UseH2C bool
|
||||||
|
|
||||||
delims render.Delims
|
delims render.Delims
|
||||||
secureJSONPrefix string
|
secureJSONPrefix string
|
||||||
HTMLRender render.HTMLRender
|
HTMLRender render.HTMLRender
|
||||||
@ -207,6 +212,15 @@ func Default() *Engine {
|
|||||||
return engine
|
return engine
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (engine *Engine) Handler() http.Handler {
|
||||||
|
if !engine.UseH2C {
|
||||||
|
return engine
|
||||||
|
}
|
||||||
|
|
||||||
|
h2s := &http2.Server{}
|
||||||
|
return h2c.NewHandler(engine, h2s)
|
||||||
|
}
|
||||||
|
|
||||||
func (engine *Engine) allocateContext() *Context {
|
func (engine *Engine) allocateContext() *Context {
|
||||||
v := make(Params, 0, engine.maxParams)
|
v := make(Params, 0, engine.maxParams)
|
||||||
skippedNodes := make([]skippedNode, 0, engine.maxSections)
|
skippedNodes := make([]skippedNode, 0, engine.maxSections)
|
||||||
@ -361,7 +375,7 @@ func (engine *Engine) Run(addr ...string) (err error) {
|
|||||||
|
|
||||||
address := resolveAddress(addr)
|
address := resolveAddress(addr)
|
||||||
debugPrint("Listening and serving HTTP on %s\n", address)
|
debugPrint("Listening and serving HTTP on %s\n", address)
|
||||||
err = http.ListenAndServe(address, engine)
|
err = http.ListenAndServe(address, engine.Handler())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -480,7 +494,7 @@ func (engine *Engine) RunTLS(addr, certFile, keyFile string) (err error) {
|
|||||||
"Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.")
|
"Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = http.ListenAndServeTLS(addr, certFile, keyFile, engine)
|
err = http.ListenAndServeTLS(addr, certFile, keyFile, engine.Handler())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -503,7 +517,7 @@ func (engine *Engine) RunUnix(file string) (err error) {
|
|||||||
defer listener.Close()
|
defer listener.Close()
|
||||||
defer os.Remove(file)
|
defer os.Remove(file)
|
||||||
|
|
||||||
err = http.Serve(listener, engine)
|
err = http.Serve(listener, engine.Handler())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -540,7 +554,7 @@ func (engine *Engine) RunListener(listener net.Listener) (err error) {
|
|||||||
"Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.")
|
"Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = http.Serve(listener, engine)
|
err = http.Serve(listener, engine.Handler())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,7 +118,7 @@ func StaticFS(relativePath string, fs http.FileSystem) gin.IRoutes {
|
|||||||
return engine().StaticFS(relativePath, fs)
|
return engine().StaticFS(relativePath, fs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use attaches a global middleware to the router. i.e. the middlewares attached though Use() will be
|
// Use attaches a global middleware to the router. i.e. the middlewares attached through Use() will be
|
||||||
// included in the handlers chain for every single request. Even 404, 405, static files...
|
// included in the handlers chain for every single request. Even 404, 405, static files...
|
||||||
// For example, this is the right place for a logger or error management middleware.
|
// For example, this is the right place for a logger or error management middleware.
|
||||||
func Use(middlewares ...gin.HandlerFunc) gin.IRoutes {
|
func Use(middlewares ...gin.HandlerFunc) gin.IRoutes {
|
||||||
|
40
gin_test.go
40
gin_test.go
@ -19,6 +19,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"golang.org/x/net/http2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func formatAsDate(t time.Time) string {
|
func formatAsDate(t time.Time) string {
|
||||||
@ -79,6 +80,39 @@ func TestLoadHTMLGlobDebugMode(t *testing.T) {
|
|||||||
assert.Equal(t, "<h1>Hello world</h1>", string(resp))
|
assert.Equal(t, "<h1>Hello world</h1>", string(resp))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestH2c(t *testing.T) {
|
||||||
|
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
r := Default()
|
||||||
|
r.UseH2C = true
|
||||||
|
r.GET("/", func(c *Context) {
|
||||||
|
c.String(200, "<h1>Hello world</h1>")
|
||||||
|
})
|
||||||
|
go http.Serve(ln, r.Handler())
|
||||||
|
defer ln.Close()
|
||||||
|
|
||||||
|
url := "http://" + ln.Addr().String() + "/"
|
||||||
|
|
||||||
|
http := http.Client{
|
||||||
|
Transport: &http2.Transport{
|
||||||
|
AllowHTTP: true,
|
||||||
|
DialTLS: func(netw, addr string, cfg *tls.Config) (net.Conn, error) {
|
||||||
|
return net.Dial(netw, addr)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := http.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, _ := ioutil.ReadAll(res.Body)
|
||||||
|
assert.Equal(t, "<h1>Hello world</h1>", string(resp))
|
||||||
|
}
|
||||||
|
|
||||||
func TestLoadHTMLGlobTestMode(t *testing.T) {
|
func TestLoadHTMLGlobTestMode(t *testing.T) {
|
||||||
ts := setupHTMLFiles(
|
ts := setupHTMLFiles(
|
||||||
t,
|
t,
|
||||||
@ -395,7 +429,6 @@ func TestNoMethodWithoutGlobalHandlers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestRebuild404Handlers(t *testing.T) {
|
func TestRebuild404Handlers(t *testing.T) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNoMethodWithGlobalHandlers(t *testing.T) {
|
func TestNoMethodWithGlobalHandlers(t *testing.T) {
|
||||||
@ -491,7 +524,7 @@ func TestEngineHandleContext(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert.NotPanics(t, func() {
|
assert.NotPanics(t, func() {
|
||||||
w := performRequest(r, "GET", "/")
|
w := PerformRequest(r, "GET", "/")
|
||||||
assert.Equal(t, 301, w.Code)
|
assert.Equal(t, 301, w.Code)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -524,7 +557,7 @@ func TestEngineHandleContextManyReEntries(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
assert.NotPanics(t, func() {
|
assert.NotPanics(t, func() {
|
||||||
w := performRequest(r, "GET", "/"+strconv.Itoa(expectValue-1)) // include 0 value
|
w := PerformRequest(r, "GET", "/"+strconv.Itoa(expectValue-1)) // include 0 value
|
||||||
assert.Equal(t, 200, w.Code)
|
assert.Equal(t, 200, w.Code)
|
||||||
assert.Equal(t, expectValue, w.Body.Len())
|
assert.Equal(t, expectValue, w.Body.Len())
|
||||||
})
|
})
|
||||||
@ -636,7 +669,6 @@ func TestPrepareTrustedCIRDsWith(t *testing.T) {
|
|||||||
assert.Nil(t, r.trustedCIDRs)
|
assert.Nil(t, r.trustedCIDRs)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseCIDR(cidr string) *net.IPNet {
|
func parseCIDR(cidr string) *net.IPNet {
|
||||||
|
@ -302,7 +302,7 @@ func TestShouldBindUri(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
path, _ := exampleFromPath("/rest/:name/:id")
|
path, _ := exampleFromPath("/rest/:name/:id")
|
||||||
w := performRequest(router, http.MethodGet, path)
|
w := PerformRequest(router, http.MethodGet, path)
|
||||||
assert.Equal(t, "ShouldBindUri test OK", w.Body.String())
|
assert.Equal(t, "ShouldBindUri test OK", w.Body.String())
|
||||||
assert.Equal(t, http.StatusOK, w.Code)
|
assert.Equal(t, http.StatusOK, w.Code)
|
||||||
}
|
}
|
||||||
@ -324,7 +324,7 @@ func TestBindUri(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
path, _ := exampleFromPath("/rest/:name/:id")
|
path, _ := exampleFromPath("/rest/:name/:id")
|
||||||
w := performRequest(router, http.MethodGet, path)
|
w := PerformRequest(router, http.MethodGet, path)
|
||||||
assert.Equal(t, "BindUri test OK", w.Body.String())
|
assert.Equal(t, "BindUri test OK", w.Body.String())
|
||||||
assert.Equal(t, http.StatusOK, w.Code)
|
assert.Equal(t, http.StatusOK, w.Code)
|
||||||
}
|
}
|
||||||
@ -342,7 +342,7 @@ func TestBindUriError(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
path1, _ := exampleFromPath("/new/rest/:num")
|
path1, _ := exampleFromPath("/new/rest/:num")
|
||||||
w1 := performRequest(router, http.MethodGet, path1)
|
w1 := PerformRequest(router, http.MethodGet, path1)
|
||||||
assert.Equal(t, http.StatusBadRequest, w1.Code)
|
assert.Equal(t, http.StatusBadRequest, w1.Code)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,7 +358,7 @@ func TestRaceContextCopy(t *testing.T) {
|
|||||||
go readWriteKeys(c.Copy())
|
go readWriteKeys(c.Copy())
|
||||||
c.String(http.StatusOK, "run OK, no panics")
|
c.String(http.StatusOK, "run OK, no panics")
|
||||||
})
|
})
|
||||||
w := performRequest(router, http.MethodGet, "/test/copy/race")
|
w := PerformRequest(router, http.MethodGet, "/test/copy/race")
|
||||||
assert.Equal(t, "run OK, no panics", w.Body.String())
|
assert.Equal(t, "run OK, no panics", w.Body.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -389,7 +389,7 @@ func TestGithubAPI(t *testing.T) {
|
|||||||
|
|
||||||
for _, route := range githubAPI {
|
for _, route := range githubAPI {
|
||||||
path, values := exampleFromPath(route.path)
|
path, values := exampleFromPath(route.path)
|
||||||
w := performRequest(router, route.method, path)
|
w := PerformRequest(router, route.method, path)
|
||||||
|
|
||||||
// TEST
|
// TEST
|
||||||
assert.Contains(t, w.Body.String(), "\"status\":\"good\"")
|
assert.Contains(t, w.Body.String(), "\"status\":\"good\"")
|
||||||
|
7
go.mod
7
go.mod
@ -4,14 +4,13 @@ go 1.13
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/gin-contrib/sse v0.1.0
|
github.com/gin-contrib/sse v0.1.0
|
||||||
github.com/go-playground/validator/v10 v10.9.0
|
github.com/go-playground/validator/v10 v10.10.0
|
||||||
github.com/goccy/go-json v0.8.1
|
github.com/goccy/go-json v0.9.0
|
||||||
github.com/json-iterator/go v1.1.12
|
github.com/json-iterator/go v1.1.12
|
||||||
github.com/mattn/go-isatty v0.0.14
|
github.com/mattn/go-isatty v0.0.14
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.7.0
|
||||||
github.com/ugorji/go/codec v1.2.6
|
github.com/ugorji/go/codec v1.2.6
|
||||||
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110
|
||||||
google.golang.org/protobuf v1.27.1
|
google.golang.org/protobuf v1.27.1
|
||||||
gopkg.in/yaml.v2 v2.4.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
)
|
)
|
||||||
|
|
||||||
retract v1.7.5
|
|
||||||
|
9
go.sum
9
go.sum
@ -10,10 +10,10 @@ github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb
|
|||||||
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
|
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
|
||||||
github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
|
github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
|
||||||
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
|
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
|
||||||
github.com/go-playground/validator/v10 v10.9.0 h1:NgTtmN58D0m8+UuxtYmGztBJB7VnPgjj221I1QHci2A=
|
github.com/go-playground/validator/v10 v10.10.0 h1:I7mrTYv78z8k8VXa/qJlOlEXn/nBh+BF8dHX5nt/dr0=
|
||||||
github.com/go-playground/validator/v10 v10.9.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
|
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
|
||||||
github.com/goccy/go-json v0.8.1 h1:4/Wjm0JIJaTDm8K1KcGrLHJoa8EsJ13YWeX+6Kfq6uI=
|
github.com/goccy/go-json v0.9.0 h1:2flW7bkbrRgU8VuDi0WXDqTmPimjv1thfxkPe8sug+8=
|
||||||
github.com/goccy/go-json v0.8.1/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
github.com/goccy/go-json v0.9.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
@ -53,6 +53,7 @@ github.com/ugorji/go/codec v1.2.6 h1:7kbGefxLoDBuYXOms4yD7223OpNMMPNPZxXk5TvFcyQ
|
|||||||
github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw=
|
github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw=
|
||||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
|
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
|
||||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
@ -31,7 +31,7 @@ func TestLogger(t *testing.T) {
|
|||||||
router.HEAD("/example", func(c *Context) {})
|
router.HEAD("/example", func(c *Context) {})
|
||||||
router.OPTIONS("/example", func(c *Context) {})
|
router.OPTIONS("/example", func(c *Context) {})
|
||||||
|
|
||||||
performRequest(router, "GET", "/example?a=100")
|
PerformRequest(router, "GET", "/example?a=100")
|
||||||
assert.Contains(t, buffer.String(), "200")
|
assert.Contains(t, buffer.String(), "200")
|
||||||
assert.Contains(t, buffer.String(), "GET")
|
assert.Contains(t, buffer.String(), "GET")
|
||||||
assert.Contains(t, buffer.String(), "/example")
|
assert.Contains(t, buffer.String(), "/example")
|
||||||
@ -41,43 +41,43 @@ func TestLogger(t *testing.T) {
|
|||||||
// like integration tests because they test the whole logging process rather
|
// like integration tests because they test the whole logging process rather
|
||||||
// than individual functions. Im not sure where these should go.
|
// than individual functions. Im not sure where these should go.
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
performRequest(router, "POST", "/example")
|
PerformRequest(router, "POST", "/example")
|
||||||
assert.Contains(t, buffer.String(), "200")
|
assert.Contains(t, buffer.String(), "200")
|
||||||
assert.Contains(t, buffer.String(), "POST")
|
assert.Contains(t, buffer.String(), "POST")
|
||||||
assert.Contains(t, buffer.String(), "/example")
|
assert.Contains(t, buffer.String(), "/example")
|
||||||
|
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
performRequest(router, "PUT", "/example")
|
PerformRequest(router, "PUT", "/example")
|
||||||
assert.Contains(t, buffer.String(), "200")
|
assert.Contains(t, buffer.String(), "200")
|
||||||
assert.Contains(t, buffer.String(), "PUT")
|
assert.Contains(t, buffer.String(), "PUT")
|
||||||
assert.Contains(t, buffer.String(), "/example")
|
assert.Contains(t, buffer.String(), "/example")
|
||||||
|
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
performRequest(router, "DELETE", "/example")
|
PerformRequest(router, "DELETE", "/example")
|
||||||
assert.Contains(t, buffer.String(), "200")
|
assert.Contains(t, buffer.String(), "200")
|
||||||
assert.Contains(t, buffer.String(), "DELETE")
|
assert.Contains(t, buffer.String(), "DELETE")
|
||||||
assert.Contains(t, buffer.String(), "/example")
|
assert.Contains(t, buffer.String(), "/example")
|
||||||
|
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
performRequest(router, "PATCH", "/example")
|
PerformRequest(router, "PATCH", "/example")
|
||||||
assert.Contains(t, buffer.String(), "200")
|
assert.Contains(t, buffer.String(), "200")
|
||||||
assert.Contains(t, buffer.String(), "PATCH")
|
assert.Contains(t, buffer.String(), "PATCH")
|
||||||
assert.Contains(t, buffer.String(), "/example")
|
assert.Contains(t, buffer.String(), "/example")
|
||||||
|
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
performRequest(router, "HEAD", "/example")
|
PerformRequest(router, "HEAD", "/example")
|
||||||
assert.Contains(t, buffer.String(), "200")
|
assert.Contains(t, buffer.String(), "200")
|
||||||
assert.Contains(t, buffer.String(), "HEAD")
|
assert.Contains(t, buffer.String(), "HEAD")
|
||||||
assert.Contains(t, buffer.String(), "/example")
|
assert.Contains(t, buffer.String(), "/example")
|
||||||
|
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
performRequest(router, "OPTIONS", "/example")
|
PerformRequest(router, "OPTIONS", "/example")
|
||||||
assert.Contains(t, buffer.String(), "200")
|
assert.Contains(t, buffer.String(), "200")
|
||||||
assert.Contains(t, buffer.String(), "OPTIONS")
|
assert.Contains(t, buffer.String(), "OPTIONS")
|
||||||
assert.Contains(t, buffer.String(), "/example")
|
assert.Contains(t, buffer.String(), "/example")
|
||||||
|
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
performRequest(router, "GET", "/notfound")
|
PerformRequest(router, "GET", "/notfound")
|
||||||
assert.Contains(t, buffer.String(), "404")
|
assert.Contains(t, buffer.String(), "404")
|
||||||
assert.Contains(t, buffer.String(), "GET")
|
assert.Contains(t, buffer.String(), "GET")
|
||||||
assert.Contains(t, buffer.String(), "/notfound")
|
assert.Contains(t, buffer.String(), "/notfound")
|
||||||
@ -95,7 +95,7 @@ func TestLoggerWithConfig(t *testing.T) {
|
|||||||
router.HEAD("/example", func(c *Context) {})
|
router.HEAD("/example", func(c *Context) {})
|
||||||
router.OPTIONS("/example", func(c *Context) {})
|
router.OPTIONS("/example", func(c *Context) {})
|
||||||
|
|
||||||
performRequest(router, "GET", "/example?a=100")
|
PerformRequest(router, "GET", "/example?a=100")
|
||||||
assert.Contains(t, buffer.String(), "200")
|
assert.Contains(t, buffer.String(), "200")
|
||||||
assert.Contains(t, buffer.String(), "GET")
|
assert.Contains(t, buffer.String(), "GET")
|
||||||
assert.Contains(t, buffer.String(), "/example")
|
assert.Contains(t, buffer.String(), "/example")
|
||||||
@ -105,43 +105,43 @@ func TestLoggerWithConfig(t *testing.T) {
|
|||||||
// like integration tests because they test the whole logging process rather
|
// like integration tests because they test the whole logging process rather
|
||||||
// than individual functions. Im not sure where these should go.
|
// than individual functions. Im not sure where these should go.
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
performRequest(router, "POST", "/example")
|
PerformRequest(router, "POST", "/example")
|
||||||
assert.Contains(t, buffer.String(), "200")
|
assert.Contains(t, buffer.String(), "200")
|
||||||
assert.Contains(t, buffer.String(), "POST")
|
assert.Contains(t, buffer.String(), "POST")
|
||||||
assert.Contains(t, buffer.String(), "/example")
|
assert.Contains(t, buffer.String(), "/example")
|
||||||
|
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
performRequest(router, "PUT", "/example")
|
PerformRequest(router, "PUT", "/example")
|
||||||
assert.Contains(t, buffer.String(), "200")
|
assert.Contains(t, buffer.String(), "200")
|
||||||
assert.Contains(t, buffer.String(), "PUT")
|
assert.Contains(t, buffer.String(), "PUT")
|
||||||
assert.Contains(t, buffer.String(), "/example")
|
assert.Contains(t, buffer.String(), "/example")
|
||||||
|
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
performRequest(router, "DELETE", "/example")
|
PerformRequest(router, "DELETE", "/example")
|
||||||
assert.Contains(t, buffer.String(), "200")
|
assert.Contains(t, buffer.String(), "200")
|
||||||
assert.Contains(t, buffer.String(), "DELETE")
|
assert.Contains(t, buffer.String(), "DELETE")
|
||||||
assert.Contains(t, buffer.String(), "/example")
|
assert.Contains(t, buffer.String(), "/example")
|
||||||
|
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
performRequest(router, "PATCH", "/example")
|
PerformRequest(router, "PATCH", "/example")
|
||||||
assert.Contains(t, buffer.String(), "200")
|
assert.Contains(t, buffer.String(), "200")
|
||||||
assert.Contains(t, buffer.String(), "PATCH")
|
assert.Contains(t, buffer.String(), "PATCH")
|
||||||
assert.Contains(t, buffer.String(), "/example")
|
assert.Contains(t, buffer.String(), "/example")
|
||||||
|
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
performRequest(router, "HEAD", "/example")
|
PerformRequest(router, "HEAD", "/example")
|
||||||
assert.Contains(t, buffer.String(), "200")
|
assert.Contains(t, buffer.String(), "200")
|
||||||
assert.Contains(t, buffer.String(), "HEAD")
|
assert.Contains(t, buffer.String(), "HEAD")
|
||||||
assert.Contains(t, buffer.String(), "/example")
|
assert.Contains(t, buffer.String(), "/example")
|
||||||
|
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
performRequest(router, "OPTIONS", "/example")
|
PerformRequest(router, "OPTIONS", "/example")
|
||||||
assert.Contains(t, buffer.String(), "200")
|
assert.Contains(t, buffer.String(), "200")
|
||||||
assert.Contains(t, buffer.String(), "OPTIONS")
|
assert.Contains(t, buffer.String(), "OPTIONS")
|
||||||
assert.Contains(t, buffer.String(), "/example")
|
assert.Contains(t, buffer.String(), "/example")
|
||||||
|
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
performRequest(router, "GET", "/notfound")
|
PerformRequest(router, "GET", "/notfound")
|
||||||
assert.Contains(t, buffer.String(), "404")
|
assert.Contains(t, buffer.String(), "404")
|
||||||
assert.Contains(t, buffer.String(), "GET")
|
assert.Contains(t, buffer.String(), "GET")
|
||||||
assert.Contains(t, buffer.String(), "/notfound")
|
assert.Contains(t, buffer.String(), "/notfound")
|
||||||
@ -169,7 +169,7 @@ func TestLoggerWithFormatter(t *testing.T) {
|
|||||||
)
|
)
|
||||||
}))
|
}))
|
||||||
router.GET("/example", func(c *Context) {})
|
router.GET("/example", func(c *Context) {})
|
||||||
performRequest(router, "GET", "/example?a=100")
|
PerformRequest(router, "GET", "/example?a=100")
|
||||||
|
|
||||||
// output test
|
// output test
|
||||||
assert.Contains(t, buffer.String(), "[FORMATTER TEST]")
|
assert.Contains(t, buffer.String(), "[FORMATTER TEST]")
|
||||||
@ -209,7 +209,7 @@ func TestLoggerWithConfigFormatting(t *testing.T) {
|
|||||||
c.Request.Header.Set("X-Forwarded-For", "20.20.20.20")
|
c.Request.Header.Set("X-Forwarded-For", "20.20.20.20")
|
||||||
gotKeys = c.Keys
|
gotKeys = c.Keys
|
||||||
})
|
})
|
||||||
performRequest(router, "GET", "/example?a=100")
|
PerformRequest(router, "GET", "/example?a=100")
|
||||||
|
|
||||||
// output test
|
// output test
|
||||||
assert.Contains(t, buffer.String(), "[FORMATTER TEST]")
|
assert.Contains(t, buffer.String(), "[FORMATTER TEST]")
|
||||||
@ -228,7 +228,6 @@ func TestLoggerWithConfigFormatting(t *testing.T) {
|
|||||||
assert.Equal(t, "/example?a=100", gotParam.Path)
|
assert.Equal(t, "/example?a=100", gotParam.Path)
|
||||||
assert.Empty(t, gotParam.ErrorMessage)
|
assert.Empty(t, gotParam.ErrorMessage)
|
||||||
assert.Equal(t, gotKeys, gotParam.Keys)
|
assert.Equal(t, gotKeys, gotParam.Keys)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDefaultLogFormatter(t *testing.T) {
|
func TestDefaultLogFormatter(t *testing.T) {
|
||||||
@ -282,7 +281,6 @@ func TestDefaultLogFormatter(t *testing.T) {
|
|||||||
|
|
||||||
assert.Equal(t, "[GIN] 2018/12/07 - 09:11:42 |\x1b[97;42m 200 \x1b[0m| 5s | 20.20.20.20 |\x1b[97;44m GET \x1b[0m \"/\"\n", defaultLogFormatter(termTrueParam))
|
assert.Equal(t, "[GIN] 2018/12/07 - 09:11:42 |\x1b[97;42m 200 \x1b[0m| 5s | 20.20.20.20 |\x1b[97;44m GET \x1b[0m \"/\"\n", defaultLogFormatter(termTrueParam))
|
||||||
assert.Equal(t, "[GIN] 2018/12/07 - 09:11:42 |\x1b[97;42m 200 \x1b[0m| 2743h29m3s | 20.20.20.20 |\x1b[97;44m GET \x1b[0m \"/\"\n", defaultLogFormatter(termTrueLongDurationParam))
|
assert.Equal(t, "[GIN] 2018/12/07 - 09:11:42 |\x1b[97;42m 200 \x1b[0m| 2743h29m3s | 20.20.20.20 |\x1b[97;44m GET \x1b[0m \"/\"\n", defaultLogFormatter(termTrueLongDurationParam))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestColorForMethod(t *testing.T) {
|
func TestColorForMethod(t *testing.T) {
|
||||||
@ -369,15 +367,15 @@ func TestErrorLogger(t *testing.T) {
|
|||||||
c.String(http.StatusInternalServerError, "hola!")
|
c.String(http.StatusInternalServerError, "hola!")
|
||||||
})
|
})
|
||||||
|
|
||||||
w := performRequest(router, "GET", "/error")
|
w := PerformRequest(router, "GET", "/error")
|
||||||
assert.Equal(t, http.StatusOK, 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, http.StatusUnauthorized, 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, http.StatusInternalServerError, 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())
|
||||||
}
|
}
|
||||||
@ -389,11 +387,11 @@ func TestLoggerWithWriterSkippingPaths(t *testing.T) {
|
|||||||
router.GET("/logged", func(c *Context) {})
|
router.GET("/logged", func(c *Context) {})
|
||||||
router.GET("/skipped", func(c *Context) {})
|
router.GET("/skipped", func(c *Context) {})
|
||||||
|
|
||||||
performRequest(router, "GET", "/logged")
|
PerformRequest(router, "GET", "/logged")
|
||||||
assert.Contains(t, buffer.String(), "200")
|
assert.Contains(t, buffer.String(), "200")
|
||||||
|
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
performRequest(router, "GET", "/skipped")
|
PerformRequest(router, "GET", "/skipped")
|
||||||
assert.Contains(t, buffer.String(), "")
|
assert.Contains(t, buffer.String(), "")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -407,11 +405,11 @@ func TestLoggerWithConfigSkippingPaths(t *testing.T) {
|
|||||||
router.GET("/logged", func(c *Context) {})
|
router.GET("/logged", func(c *Context) {})
|
||||||
router.GET("/skipped", func(c *Context) {})
|
router.GET("/skipped", func(c *Context) {})
|
||||||
|
|
||||||
performRequest(router, "GET", "/logged")
|
PerformRequest(router, "GET", "/logged")
|
||||||
assert.Contains(t, buffer.String(), "200")
|
assert.Contains(t, buffer.String(), "200")
|
||||||
|
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
performRequest(router, "GET", "/skipped")
|
PerformRequest(router, "GET", "/skipped")
|
||||||
assert.Contains(t, buffer.String(), "")
|
assert.Contains(t, buffer.String(), "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ func TestMiddlewareGeneralCase(t *testing.T) {
|
|||||||
signature += " XX "
|
signature += " XX "
|
||||||
})
|
})
|
||||||
// RUN
|
// RUN
|
||||||
w := performRequest(router, "GET", "/")
|
w := PerformRequest(router, "GET", "/")
|
||||||
|
|
||||||
// TEST
|
// TEST
|
||||||
assert.Equal(t, http.StatusOK, w.Code)
|
assert.Equal(t, http.StatusOK, w.Code)
|
||||||
@ -71,7 +71,7 @@ func TestMiddlewareNoRoute(t *testing.T) {
|
|||||||
signature += " X "
|
signature += " X "
|
||||||
})
|
})
|
||||||
// RUN
|
// RUN
|
||||||
w := performRequest(router, "GET", "/")
|
w := PerformRequest(router, "GET", "/")
|
||||||
|
|
||||||
// TEST
|
// TEST
|
||||||
assert.Equal(t, http.StatusNotFound, w.Code)
|
assert.Equal(t, http.StatusNotFound, w.Code)
|
||||||
@ -108,7 +108,7 @@ func TestMiddlewareNoMethodEnabled(t *testing.T) {
|
|||||||
signature += " XX "
|
signature += " XX "
|
||||||
})
|
})
|
||||||
// RUN
|
// RUN
|
||||||
w := performRequest(router, "GET", "/")
|
w := PerformRequest(router, "GET", "/")
|
||||||
|
|
||||||
// TEST
|
// TEST
|
||||||
assert.Equal(t, http.StatusMethodNotAllowed, w.Code)
|
assert.Equal(t, http.StatusMethodNotAllowed, w.Code)
|
||||||
@ -149,7 +149,7 @@ func TestMiddlewareNoMethodDisabled(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// RUN
|
// RUN
|
||||||
w := performRequest(router, "GET", "/")
|
w := PerformRequest(router, "GET", "/")
|
||||||
|
|
||||||
// TEST
|
// TEST
|
||||||
assert.Equal(t, http.StatusNotFound, w.Code)
|
assert.Equal(t, http.StatusNotFound, w.Code)
|
||||||
@ -175,7 +175,7 @@ func TestMiddlewareAbort(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// RUN
|
// RUN
|
||||||
w := performRequest(router, "GET", "/")
|
w := PerformRequest(router, "GET", "/")
|
||||||
|
|
||||||
// TEST
|
// TEST
|
||||||
assert.Equal(t, http.StatusUnauthorized, w.Code)
|
assert.Equal(t, http.StatusUnauthorized, w.Code)
|
||||||
@ -190,14 +190,13 @@ func TestMiddlewareAbortHandlersChainAndNext(t *testing.T) {
|
|||||||
c.Next()
|
c.Next()
|
||||||
c.AbortWithStatus(http.StatusGone)
|
c.AbortWithStatus(http.StatusGone)
|
||||||
signature += "B"
|
signature += "B"
|
||||||
|
|
||||||
})
|
})
|
||||||
router.GET("/", func(c *Context) {
|
router.GET("/", func(c *Context) {
|
||||||
signature += "C"
|
signature += "C"
|
||||||
c.Next()
|
c.Next()
|
||||||
})
|
})
|
||||||
// RUN
|
// RUN
|
||||||
w := performRequest(router, "GET", "/")
|
w := PerformRequest(router, "GET", "/")
|
||||||
|
|
||||||
// TEST
|
// TEST
|
||||||
assert.Equal(t, http.StatusGone, w.Code)
|
assert.Equal(t, http.StatusGone, w.Code)
|
||||||
@ -220,7 +219,7 @@ func TestMiddlewareFailHandlersChain(t *testing.T) {
|
|||||||
signature += "C"
|
signature += "C"
|
||||||
})
|
})
|
||||||
// RUN
|
// RUN
|
||||||
w := performRequest(router, "GET", "/")
|
w := PerformRequest(router, "GET", "/")
|
||||||
|
|
||||||
// TEST
|
// TEST
|
||||||
assert.Equal(t, http.StatusInternalServerError, w.Code)
|
assert.Equal(t, http.StatusInternalServerError, w.Code)
|
||||||
@ -247,7 +246,7 @@ func TestMiddlewareWrite(t *testing.T) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
w := performRequest(router, "GET", "/")
|
w := PerformRequest(router, "GET", "/")
|
||||||
|
|
||||||
assert.Equal(t, http.StatusBadRequest, 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))
|
||||||
|
@ -27,7 +27,7 @@ func TestPanicClean(t *testing.T) {
|
|||||||
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",
|
||||||
header{
|
header{
|
||||||
Key: "Host",
|
Key: "Host",
|
||||||
Value: "www.google.com",
|
Value: "www.google.com",
|
||||||
@ -57,7 +57,7 @@ func TestPanicInHandler(t *testing.T) {
|
|||||||
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, http.StatusInternalServerError, w.Code)
|
assert.Equal(t, http.StatusInternalServerError, w.Code)
|
||||||
assert.Contains(t, buffer.String(), "panic recovered")
|
assert.Contains(t, buffer.String(), "panic recovered")
|
||||||
@ -68,7 +68,7 @@ func TestPanicInHandler(t *testing.T) {
|
|||||||
// Debug mode prints the request
|
// Debug mode prints the request
|
||||||
SetMode(DebugMode)
|
SetMode(DebugMode)
|
||||||
// RUN
|
// RUN
|
||||||
w = performRequest(router, "GET", "/recovery")
|
w = PerformRequest(router, "GET", "/recovery")
|
||||||
// TEST
|
// TEST
|
||||||
assert.Equal(t, http.StatusInternalServerError, w.Code)
|
assert.Equal(t, http.StatusInternalServerError, w.Code)
|
||||||
assert.Contains(t, buffer.String(), "GET /recovery")
|
assert.Contains(t, buffer.String(), "GET /recovery")
|
||||||
@ -85,7 +85,7 @@ func TestPanicWithAbort(t *testing.T) {
|
|||||||
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, http.StatusBadRequest, w.Code)
|
assert.Equal(t, http.StatusBadRequest, w.Code)
|
||||||
}
|
}
|
||||||
@ -122,7 +122,6 @@ func TestPanicWithBrokenPipe(t *testing.T) {
|
|||||||
|
|
||||||
for errno, expectMsg := range expectMsgs {
|
for errno, expectMsg := range expectMsgs {
|
||||||
t.Run(expectMsg, func(t *testing.T) {
|
t.Run(expectMsg, func(t *testing.T) {
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
|
|
||||||
router := New()
|
router := New()
|
||||||
@ -137,7 +136,7 @@ func TestPanicWithBrokenPipe(t *testing.T) {
|
|||||||
panic(e)
|
panic(e)
|
||||||
})
|
})
|
||||||
// RUN
|
// RUN
|
||||||
w := performRequest(router, "GET", "/recovery")
|
w := PerformRequest(router, "GET", "/recovery")
|
||||||
// TEST
|
// TEST
|
||||||
assert.Equal(t, expectCode, w.Code)
|
assert.Equal(t, expectCode, w.Code)
|
||||||
assert.Contains(t, strings.ToLower(buf.String()), expectMsg)
|
assert.Contains(t, strings.ToLower(buf.String()), expectMsg)
|
||||||
@ -158,7 +157,7 @@ func TestCustomRecoveryWithWriter(t *testing.T) {
|
|||||||
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, http.StatusBadRequest, w.Code)
|
assert.Equal(t, http.StatusBadRequest, w.Code)
|
||||||
assert.Contains(t, buffer.String(), "panic recovered")
|
assert.Contains(t, buffer.String(), "panic recovered")
|
||||||
@ -169,7 +168,7 @@ func TestCustomRecoveryWithWriter(t *testing.T) {
|
|||||||
// Debug mode prints the request
|
// Debug mode prints the request
|
||||||
SetMode(DebugMode)
|
SetMode(DebugMode)
|
||||||
// RUN
|
// RUN
|
||||||
w = performRequest(router, "GET", "/recovery")
|
w = PerformRequest(router, "GET", "/recovery")
|
||||||
// TEST
|
// TEST
|
||||||
assert.Equal(t, http.StatusBadRequest, w.Code)
|
assert.Equal(t, http.StatusBadRequest, w.Code)
|
||||||
assert.Contains(t, buffer.String(), "GET /recovery")
|
assert.Contains(t, buffer.String(), "GET /recovery")
|
||||||
@ -193,7 +192,7 @@ func TestCustomRecovery(t *testing.T) {
|
|||||||
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, http.StatusBadRequest, w.Code)
|
assert.Equal(t, http.StatusBadRequest, w.Code)
|
||||||
assert.Contains(t, buffer.String(), "panic recovered")
|
assert.Contains(t, buffer.String(), "panic recovered")
|
||||||
@ -204,7 +203,7 @@ func TestCustomRecovery(t *testing.T) {
|
|||||||
// Debug mode prints the request
|
// Debug mode prints the request
|
||||||
SetMode(DebugMode)
|
SetMode(DebugMode)
|
||||||
// RUN
|
// RUN
|
||||||
w = performRequest(router, "GET", "/recovery")
|
w = PerformRequest(router, "GET", "/recovery")
|
||||||
// TEST
|
// TEST
|
||||||
assert.Equal(t, http.StatusBadRequest, w.Code)
|
assert.Equal(t, http.StatusBadRequest, w.Code)
|
||||||
assert.Contains(t, buffer.String(), "GET /recovery")
|
assert.Contains(t, buffer.String(), "GET /recovery")
|
||||||
@ -228,7 +227,7 @@ func TestRecoveryWithWriterWithCustomRecovery(t *testing.T) {
|
|||||||
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, http.StatusBadRequest, w.Code)
|
assert.Equal(t, http.StatusBadRequest, w.Code)
|
||||||
assert.Contains(t, buffer.String(), "panic recovered")
|
assert.Contains(t, buffer.String(), "panic recovered")
|
||||||
@ -239,7 +238,7 @@ func TestRecoveryWithWriterWithCustomRecovery(t *testing.T) {
|
|||||||
// Debug mode prints the request
|
// Debug mode prints the request
|
||||||
SetMode(DebugMode)
|
SetMode(DebugMode)
|
||||||
// RUN
|
// RUN
|
||||||
w = performRequest(router, "GET", "/recovery")
|
w = PerformRequest(router, "GET", "/recovery")
|
||||||
// TEST
|
// TEST
|
||||||
assert.Equal(t, http.StatusBadRequest, w.Code)
|
assert.Equal(t, http.StatusBadRequest, w.Code)
|
||||||
assert.Contains(t, buffer.String(), "GET /recovery")
|
assert.Contains(t, buffer.String(), "GET /recovery")
|
||||||
|
@ -80,11 +80,11 @@ func performRequestInGroup(t *testing.T, method string) {
|
|||||||
panic("unknown method")
|
panic("unknown method")
|
||||||
}
|
}
|
||||||
|
|
||||||
w := performRequest(router, method, "/v1/login/test")
|
w := PerformRequest(router, method, "/v1/login/test")
|
||||||
assert.Equal(t, http.StatusBadRequest, 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, http.StatusBadRequest, 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())
|
||||||
}
|
}
|
||||||
|
111
routes_test.go
111
routes_test.go
@ -21,7 +21,8 @@ type header struct {
|
|||||||
Value string
|
Value string
|
||||||
}
|
}
|
||||||
|
|
||||||
func performRequest(r http.Handler, method, path string, headers ...header) *httptest.ResponseRecorder {
|
// PerformRequest for testing gin router.
|
||||||
|
func PerformRequest(r http.Handler, method, path string, headers ...header) *httptest.ResponseRecorder {
|
||||||
req := httptest.NewRequest(method, path, nil)
|
req := httptest.NewRequest(method, path, nil)
|
||||||
for _, h := range headers {
|
for _, h := range headers {
|
||||||
req.Header.Add(h.Key, h.Value)
|
req.Header.Add(h.Key, h.Value)
|
||||||
@ -42,11 +43,11 @@ func testRouteOK(method string, t *testing.T) {
|
|||||||
passed = true
|
passed = true
|
||||||
})
|
})
|
||||||
|
|
||||||
w := performRequest(r, method, "/test")
|
w := PerformRequest(r, method, "/test")
|
||||||
assert.True(t, passed)
|
assert.True(t, passed)
|
||||||
assert.Equal(t, http.StatusOK, w.Code)
|
assert.Equal(t, http.StatusOK, w.Code)
|
||||||
|
|
||||||
performRequest(r, method, "/test2")
|
PerformRequest(r, method, "/test2")
|
||||||
assert.True(t, passedAny)
|
assert.True(t, passedAny)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,7 +59,7 @@ func testRouteNotOK(method string, t *testing.T) {
|
|||||||
passed = true
|
passed = true
|
||||||
})
|
})
|
||||||
|
|
||||||
w := performRequest(router, method, "/test")
|
w := PerformRequest(router, method, "/test")
|
||||||
|
|
||||||
assert.False(t, passed)
|
assert.False(t, passed)
|
||||||
assert.Equal(t, http.StatusNotFound, w.Code)
|
assert.Equal(t, http.StatusNotFound, w.Code)
|
||||||
@ -79,7 +80,7 @@ func testRouteNotOK2(method string, t *testing.T) {
|
|||||||
passed = true
|
passed = true
|
||||||
})
|
})
|
||||||
|
|
||||||
w := performRequest(router, method, "/test")
|
w := PerformRequest(router, method, "/test")
|
||||||
|
|
||||||
assert.False(t, passed)
|
assert.False(t, passed)
|
||||||
assert.Equal(t, http.StatusMethodNotAllowed, w.Code)
|
assert.Equal(t, http.StatusMethodNotAllowed, w.Code)
|
||||||
@ -99,7 +100,7 @@ func TestRouterMethod(t *testing.T) {
|
|||||||
c.String(http.StatusOK, "sup3")
|
c.String(http.StatusOK, "sup3")
|
||||||
})
|
})
|
||||||
|
|
||||||
w := performRequest(router, http.MethodPut, "/hey")
|
w := PerformRequest(router, http.MethodPut, "/hey")
|
||||||
|
|
||||||
assert.Equal(t, http.StatusOK, w.Code)
|
assert.Equal(t, http.StatusOK, w.Code)
|
||||||
assert.Equal(t, "called", w.Body.String())
|
assert.Equal(t, "called", w.Body.String())
|
||||||
@ -150,50 +151,50 @@ func TestRouteRedirectTrailingSlash(t *testing.T) {
|
|||||||
router.POST("/path3", func(c *Context) {})
|
router.POST("/path3", func(c *Context) {})
|
||||||
router.PUT("/path4/", func(c *Context) {})
|
router.PUT("/path4/", func(c *Context) {})
|
||||||
|
|
||||||
w := performRequest(router, http.MethodGet, "/path/")
|
w := PerformRequest(router, http.MethodGet, "/path/")
|
||||||
assert.Equal(t, "/path", w.Header().Get("Location"))
|
assert.Equal(t, "/path", w.Header().Get("Location"))
|
||||||
assert.Equal(t, http.StatusMovedPermanently, w.Code)
|
assert.Equal(t, http.StatusMovedPermanently, w.Code)
|
||||||
|
|
||||||
w = performRequest(router, http.MethodGet, "/path2")
|
w = PerformRequest(router, http.MethodGet, "/path2")
|
||||||
assert.Equal(t, "/path2/", w.Header().Get("Location"))
|
assert.Equal(t, "/path2/", w.Header().Get("Location"))
|
||||||
assert.Equal(t, http.StatusMovedPermanently, w.Code)
|
assert.Equal(t, http.StatusMovedPermanently, w.Code)
|
||||||
|
|
||||||
w = performRequest(router, http.MethodPost, "/path3/")
|
w = PerformRequest(router, http.MethodPost, "/path3/")
|
||||||
assert.Equal(t, "/path3", w.Header().Get("Location"))
|
assert.Equal(t, "/path3", w.Header().Get("Location"))
|
||||||
assert.Equal(t, http.StatusTemporaryRedirect, w.Code)
|
assert.Equal(t, http.StatusTemporaryRedirect, w.Code)
|
||||||
|
|
||||||
w = performRequest(router, http.MethodPut, "/path4")
|
w = PerformRequest(router, http.MethodPut, "/path4")
|
||||||
assert.Equal(t, "/path4/", w.Header().Get("Location"))
|
assert.Equal(t, "/path4/", w.Header().Get("Location"))
|
||||||
assert.Equal(t, http.StatusTemporaryRedirect, w.Code)
|
assert.Equal(t, http.StatusTemporaryRedirect, w.Code)
|
||||||
|
|
||||||
w = performRequest(router, http.MethodGet, "/path")
|
w = PerformRequest(router, http.MethodGet, "/path")
|
||||||
assert.Equal(t, http.StatusOK, w.Code)
|
assert.Equal(t, http.StatusOK, w.Code)
|
||||||
|
|
||||||
w = performRequest(router, http.MethodGet, "/path2/")
|
w = PerformRequest(router, http.MethodGet, "/path2/")
|
||||||
assert.Equal(t, http.StatusOK, w.Code)
|
assert.Equal(t, http.StatusOK, w.Code)
|
||||||
|
|
||||||
w = performRequest(router, http.MethodPost, "/path3")
|
w = PerformRequest(router, http.MethodPost, "/path3")
|
||||||
assert.Equal(t, http.StatusOK, w.Code)
|
assert.Equal(t, http.StatusOK, w.Code)
|
||||||
|
|
||||||
w = performRequest(router, http.MethodPut, "/path4/")
|
w = PerformRequest(router, http.MethodPut, "/path4/")
|
||||||
assert.Equal(t, http.StatusOK, w.Code)
|
assert.Equal(t, http.StatusOK, w.Code)
|
||||||
|
|
||||||
w = performRequest(router, http.MethodGet, "/path2", header{Key: "X-Forwarded-Prefix", Value: "/api"})
|
w = PerformRequest(router, http.MethodGet, "/path2", header{Key: "X-Forwarded-Prefix", Value: "/api"})
|
||||||
assert.Equal(t, "/api/path2/", w.Header().Get("Location"))
|
assert.Equal(t, "/api/path2/", w.Header().Get("Location"))
|
||||||
assert.Equal(t, 301, w.Code)
|
assert.Equal(t, 301, w.Code)
|
||||||
|
|
||||||
w = performRequest(router, http.MethodGet, "/path2/", header{Key: "X-Forwarded-Prefix", Value: "/api/"})
|
w = PerformRequest(router, http.MethodGet, "/path2/", header{Key: "X-Forwarded-Prefix", Value: "/api/"})
|
||||||
assert.Equal(t, 200, w.Code)
|
assert.Equal(t, 200, w.Code)
|
||||||
|
|
||||||
router.RedirectTrailingSlash = false
|
router.RedirectTrailingSlash = false
|
||||||
|
|
||||||
w = performRequest(router, http.MethodGet, "/path/")
|
w = PerformRequest(router, http.MethodGet, "/path/")
|
||||||
assert.Equal(t, http.StatusNotFound, w.Code)
|
assert.Equal(t, http.StatusNotFound, w.Code)
|
||||||
w = performRequest(router, http.MethodGet, "/path2")
|
w = PerformRequest(router, http.MethodGet, "/path2")
|
||||||
assert.Equal(t, http.StatusNotFound, w.Code)
|
assert.Equal(t, http.StatusNotFound, w.Code)
|
||||||
w = performRequest(router, http.MethodPost, "/path3/")
|
w = PerformRequest(router, http.MethodPost, "/path3/")
|
||||||
assert.Equal(t, http.StatusNotFound, w.Code)
|
assert.Equal(t, http.StatusNotFound, w.Code)
|
||||||
w = performRequest(router, http.MethodPut, "/path4")
|
w = PerformRequest(router, http.MethodPut, "/path4")
|
||||||
assert.Equal(t, http.StatusNotFound, w.Code)
|
assert.Equal(t, http.StatusNotFound, w.Code)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,19 +208,19 @@ func TestRouteRedirectFixedPath(t *testing.T) {
|
|||||||
router.POST("/PATH3", func(c *Context) {})
|
router.POST("/PATH3", func(c *Context) {})
|
||||||
router.POST("/Path4/", func(c *Context) {})
|
router.POST("/Path4/", func(c *Context) {})
|
||||||
|
|
||||||
w := performRequest(router, http.MethodGet, "/PATH")
|
w := PerformRequest(router, http.MethodGet, "/PATH")
|
||||||
assert.Equal(t, "/path", w.Header().Get("Location"))
|
assert.Equal(t, "/path", w.Header().Get("Location"))
|
||||||
assert.Equal(t, http.StatusMovedPermanently, w.Code)
|
assert.Equal(t, http.StatusMovedPermanently, w.Code)
|
||||||
|
|
||||||
w = performRequest(router, http.MethodGet, "/path2")
|
w = PerformRequest(router, http.MethodGet, "/path2")
|
||||||
assert.Equal(t, "/Path2", w.Header().Get("Location"))
|
assert.Equal(t, "/Path2", w.Header().Get("Location"))
|
||||||
assert.Equal(t, http.StatusMovedPermanently, w.Code)
|
assert.Equal(t, http.StatusMovedPermanently, w.Code)
|
||||||
|
|
||||||
w = performRequest(router, http.MethodPost, "/path3")
|
w = PerformRequest(router, http.MethodPost, "/path3")
|
||||||
assert.Equal(t, "/PATH3", w.Header().Get("Location"))
|
assert.Equal(t, "/PATH3", w.Header().Get("Location"))
|
||||||
assert.Equal(t, http.StatusTemporaryRedirect, w.Code)
|
assert.Equal(t, http.StatusTemporaryRedirect, w.Code)
|
||||||
|
|
||||||
w = performRequest(router, http.MethodPost, "/path4")
|
w = PerformRequest(router, http.MethodPost, "/path4")
|
||||||
assert.Equal(t, "/Path4/", w.Header().Get("Location"))
|
assert.Equal(t, "/Path4/", w.Header().Get("Location"))
|
||||||
assert.Equal(t, http.StatusTemporaryRedirect, w.Code)
|
assert.Equal(t, http.StatusTemporaryRedirect, w.Code)
|
||||||
}
|
}
|
||||||
@ -248,7 +249,7 @@ func TestRouteParamsByName(t *testing.T) {
|
|||||||
assert.False(t, ok)
|
assert.False(t, ok)
|
||||||
})
|
})
|
||||||
|
|
||||||
w := performRequest(router, http.MethodGet, "/test/john/smith/is/super/great")
|
w := PerformRequest(router, http.MethodGet, "/test/john/smith/is/super/great")
|
||||||
|
|
||||||
assert.Equal(t, http.StatusOK, w.Code)
|
assert.Equal(t, http.StatusOK, w.Code)
|
||||||
assert.Equal(t, "john", name)
|
assert.Equal(t, "john", name)
|
||||||
@ -281,7 +282,7 @@ func TestRouteParamsByNameWithExtraSlash(t *testing.T) {
|
|||||||
assert.False(t, ok)
|
assert.False(t, ok)
|
||||||
})
|
})
|
||||||
|
|
||||||
w := performRequest(router, http.MethodGet, "//test//john//smith//is//super//great")
|
w := PerformRequest(router, http.MethodGet, "//test//john//smith//is//super//great")
|
||||||
|
|
||||||
assert.Equal(t, http.StatusOK, w.Code)
|
assert.Equal(t, http.StatusOK, w.Code)
|
||||||
assert.Equal(t, "john", name)
|
assert.Equal(t, "john", name)
|
||||||
@ -309,16 +310,16 @@ func TestRouteStaticFile(t *testing.T) {
|
|||||||
router.Static("/using_static", dir)
|
router.Static("/using_static", dir)
|
||||||
router.StaticFile("/result", f.Name())
|
router.StaticFile("/result", f.Name())
|
||||||
|
|
||||||
w := performRequest(router, http.MethodGet, "/using_static/"+filename)
|
w := PerformRequest(router, http.MethodGet, "/using_static/"+filename)
|
||||||
w2 := performRequest(router, http.MethodGet, "/result")
|
w2 := PerformRequest(router, http.MethodGet, "/result")
|
||||||
|
|
||||||
assert.Equal(t, w, w2)
|
assert.Equal(t, w, w2)
|
||||||
assert.Equal(t, http.StatusOK, 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.Header().Get("Content-Type"))
|
assert.Equal(t, "text/plain; charset=utf-8", w.Header().Get("Content-Type"))
|
||||||
|
|
||||||
w3 := performRequest(router, http.MethodHead, "/using_static/"+filename)
|
w3 := PerformRequest(router, http.MethodHead, "/using_static/"+filename)
|
||||||
w4 := performRequest(router, http.MethodHead, "/result")
|
w4 := PerformRequest(router, http.MethodHead, "/result")
|
||||||
|
|
||||||
assert.Equal(t, w3, w4)
|
assert.Equal(t, w3, w4)
|
||||||
assert.Equal(t, http.StatusOK, w3.Code)
|
assert.Equal(t, http.StatusOK, w3.Code)
|
||||||
@ -329,7 +330,7 @@ func TestRouteStaticListingDir(t *testing.T) {
|
|||||||
router := New()
|
router := New()
|
||||||
router.StaticFS("/", Dir("./", true))
|
router.StaticFS("/", Dir("./", true))
|
||||||
|
|
||||||
w := performRequest(router, http.MethodGet, "/")
|
w := PerformRequest(router, http.MethodGet, "/")
|
||||||
|
|
||||||
assert.Equal(t, http.StatusOK, 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")
|
||||||
@ -341,7 +342,7 @@ func TestRouteStaticNoListing(t *testing.T) {
|
|||||||
router := New()
|
router := New()
|
||||||
router.Static("/", "./")
|
router.Static("/", "./")
|
||||||
|
|
||||||
w := performRequest(router, http.MethodGet, "/")
|
w := PerformRequest(router, http.MethodGet, "/")
|
||||||
|
|
||||||
assert.Equal(t, http.StatusNotFound, 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")
|
||||||
@ -356,7 +357,7 @@ func TestRouterMiddlewareAndStatic(t *testing.T) {
|
|||||||
})
|
})
|
||||||
static.Static("/", "./")
|
static.Static("/", "./")
|
||||||
|
|
||||||
w := performRequest(router, http.MethodGet, "/gin.go")
|
w := PerformRequest(router, http.MethodGet, "/gin.go")
|
||||||
|
|
||||||
assert.Equal(t, http.StatusOK, 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")
|
||||||
@ -372,13 +373,13 @@ func TestRouteNotAllowedEnabled(t *testing.T) {
|
|||||||
router := New()
|
router := New()
|
||||||
router.HandleMethodNotAllowed = true
|
router.HandleMethodNotAllowed = true
|
||||||
router.POST("/path", func(c *Context) {})
|
router.POST("/path", func(c *Context) {})
|
||||||
w := performRequest(router, http.MethodGet, "/path")
|
w := PerformRequest(router, http.MethodGet, "/path")
|
||||||
assert.Equal(t, http.StatusMethodNotAllowed, w.Code)
|
assert.Equal(t, http.StatusMethodNotAllowed, 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, http.MethodGet, "/path")
|
w = PerformRequest(router, http.MethodGet, "/path")
|
||||||
assert.Equal(t, "responseText", w.Body.String())
|
assert.Equal(t, "responseText", w.Body.String())
|
||||||
assert.Equal(t, http.StatusTeapot, w.Code)
|
assert.Equal(t, http.StatusTeapot, w.Code)
|
||||||
}
|
}
|
||||||
@ -389,7 +390,7 @@ func TestRouteNotAllowedEnabled2(t *testing.T) {
|
|||||||
// add one methodTree to trees
|
// add one methodTree to trees
|
||||||
router.addRoute(http.MethodPost, "/", HandlersChain{func(_ *Context) {}})
|
router.addRoute(http.MethodPost, "/", HandlersChain{func(_ *Context) {}})
|
||||||
router.GET("/path2", func(c *Context) {})
|
router.GET("/path2", func(c *Context) {})
|
||||||
w := performRequest(router, http.MethodPost, "/path2")
|
w := PerformRequest(router, http.MethodPost, "/path2")
|
||||||
assert.Equal(t, http.StatusMethodNotAllowed, w.Code)
|
assert.Equal(t, http.StatusMethodNotAllowed, w.Code)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -397,13 +398,13 @@ 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, http.MethodGet, "/path")
|
w := PerformRequest(router, http.MethodGet, "/path")
|
||||||
assert.Equal(t, http.StatusNotFound, 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, http.MethodGet, "/path")
|
w = PerformRequest(router, http.MethodGet, "/path")
|
||||||
assert.Equal(t, "404 page not found", w.Body.String())
|
assert.Equal(t, "404 page not found", w.Body.String())
|
||||||
assert.Equal(t, http.StatusNotFound, w.Code)
|
assert.Equal(t, http.StatusNotFound, w.Code)
|
||||||
}
|
}
|
||||||
@ -423,7 +424,7 @@ func TestRouterNotFoundWithRemoveExtraSlash(t *testing.T) {
|
|||||||
{"/nope", http.StatusNotFound, ""}, // 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 != http.StatusNotFound {
|
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")))
|
||||||
@ -453,7 +454,7 @@ func TestRouterNotFound(t *testing.T) {
|
|||||||
{"/nope", http.StatusNotFound, ""}, // NotFound
|
{"/nope", http.StatusNotFound, ""}, // NotFound
|
||||||
}
|
}
|
||||||
for _, tr := range testRoutes {
|
for _, tr := range testRoutes {
|
||||||
w := performRequest(router, http.MethodGet, tr.route)
|
w := PerformRequest(router, http.MethodGet, tr.route)
|
||||||
assert.Equal(t, tr.code, w.Code)
|
assert.Equal(t, tr.code, w.Code)
|
||||||
if w.Code != http.StatusNotFound {
|
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")))
|
||||||
@ -466,20 +467,20 @@ func TestRouterNotFound(t *testing.T) {
|
|||||||
c.AbortWithStatus(http.StatusNotFound)
|
c.AbortWithStatus(http.StatusNotFound)
|
||||||
notFound = true
|
notFound = true
|
||||||
})
|
})
|
||||||
w := performRequest(router, http.MethodGet, "/nope")
|
w := PerformRequest(router, http.MethodGet, "/nope")
|
||||||
assert.Equal(t, http.StatusNotFound, 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, http.MethodPatch, "/path/")
|
w = PerformRequest(router, http.MethodPatch, "/path/")
|
||||||
assert.Equal(t, http.StatusTemporaryRedirect, 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, http.MethodGet, "/")
|
w = PerformRequest(router, http.MethodGet, "/")
|
||||||
assert.Equal(t, http.StatusNotFound, w.Code)
|
assert.Equal(t, http.StatusNotFound, w.Code)
|
||||||
|
|
||||||
// Reproduction test for the bug of issue #2843
|
// Reproduction test for the bug of issue #2843
|
||||||
@ -492,9 +493,9 @@ func TestRouterNotFound(t *testing.T) {
|
|||||||
router.GET("/logout", func(c *Context) {
|
router.GET("/logout", func(c *Context) {
|
||||||
c.String(200, "logout")
|
c.String(200, "logout")
|
||||||
})
|
})
|
||||||
w = performRequest(router, http.MethodGet, "/login")
|
w = PerformRequest(router, http.MethodGet, "/login")
|
||||||
assert.Equal(t, "login", w.Body.String())
|
assert.Equal(t, "login", w.Body.String())
|
||||||
w = performRequest(router, http.MethodGet, "/logout")
|
w = PerformRequest(router, http.MethodGet, "/logout")
|
||||||
assert.Equal(t, "logout", w.Body.String())
|
assert.Equal(t, "logout", w.Body.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -505,10 +506,10 @@ func TestRouterStaticFSNotFound(t *testing.T) {
|
|||||||
c.String(404, "non existent")
|
c.String(404, "non existent")
|
||||||
})
|
})
|
||||||
|
|
||||||
w := performRequest(router, http.MethodGet, "/nonexistent")
|
w := PerformRequest(router, http.MethodGet, "/nonexistent")
|
||||||
assert.Equal(t, "non existent", w.Body.String())
|
assert.Equal(t, "non existent", w.Body.String())
|
||||||
|
|
||||||
w = performRequest(router, http.MethodHead, "/nonexistent")
|
w = PerformRequest(router, http.MethodHead, "/nonexistent")
|
||||||
assert.Equal(t, "non existent", w.Body.String())
|
assert.Equal(t, "non existent", w.Body.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -518,7 +519,7 @@ func TestRouterStaticFSFileNotFound(t *testing.T) {
|
|||||||
router.StaticFS("/", http.FileSystem(http.Dir(".")))
|
router.StaticFS("/", http.FileSystem(http.Dir(".")))
|
||||||
|
|
||||||
assert.NotPanics(t, func() {
|
assert.NotPanics(t, func() {
|
||||||
performRequest(router, http.MethodGet, "/nonexistent")
|
PerformRequest(router, http.MethodGet, "/nonexistent")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -535,11 +536,11 @@ func TestMiddlewareCalledOnceByRouterStaticFSNotFound(t *testing.T) {
|
|||||||
router.StaticFS("/", http.FileSystem(http.Dir("/thisreallydoesntexist/")))
|
router.StaticFS("/", http.FileSystem(http.Dir("/thisreallydoesntexist/")))
|
||||||
|
|
||||||
// First access
|
// First access
|
||||||
performRequest(router, http.MethodGet, "/nonexistent")
|
PerformRequest(router, http.MethodGet, "/nonexistent")
|
||||||
assert.Equal(t, 1, middlewareCalledNum)
|
assert.Equal(t, 1, middlewareCalledNum)
|
||||||
|
|
||||||
// Second access
|
// Second access
|
||||||
performRequest(router, http.MethodHead, "/nonexistent")
|
PerformRequest(router, http.MethodHead, "/nonexistent")
|
||||||
assert.Equal(t, 2, middlewareCalledNum)
|
assert.Equal(t, 2, middlewareCalledNum)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -558,7 +559,7 @@ func TestRouteRawPath(t *testing.T) {
|
|||||||
assert.Equal(t, "222", num)
|
assert.Equal(t, "222", num)
|
||||||
})
|
})
|
||||||
|
|
||||||
w := performRequest(route, http.MethodPost, "/project/Some%2FOther%2FProject/build/222")
|
w := PerformRequest(route, http.MethodPost, "/project/Some%2FOther%2FProject/build/222")
|
||||||
assert.Equal(t, http.StatusOK, w.Code)
|
assert.Equal(t, http.StatusOK, w.Code)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -578,7 +579,7 @@ func TestRouteRawPathNoUnescape(t *testing.T) {
|
|||||||
assert.Equal(t, "333", num)
|
assert.Equal(t, "333", num)
|
||||||
})
|
})
|
||||||
|
|
||||||
w := performRequest(route, http.MethodPost, "/project/Some%2FOther%2FProject/build/333")
|
w := PerformRequest(route, http.MethodPost, "/project/Some%2FOther%2FProject/build/333")
|
||||||
assert.Equal(t, http.StatusOK, w.Code)
|
assert.Equal(t, http.StatusOK, w.Code)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -589,7 +590,7 @@ func TestRouteServeErrorWithWriteHeader(t *testing.T) {
|
|||||||
c.Next()
|
c.Next()
|
||||||
})
|
})
|
||||||
|
|
||||||
w := performRequest(route, http.MethodGet, "/NotFound")
|
w := PerformRequest(route, http.MethodGet, "/NotFound")
|
||||||
assert.Equal(t, 421, w.Code)
|
assert.Equal(t, 421, w.Code)
|
||||||
assert.Equal(t, 0, w.Body.Len())
|
assert.Equal(t, 0, w.Body.Len())
|
||||||
}
|
}
|
||||||
@ -623,7 +624,7 @@ func TestRouteContextHoldsFullPath(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, route := range routes {
|
for _, route := range routes {
|
||||||
w := performRequest(router, http.MethodGet, route)
|
w := PerformRequest(router, http.MethodGet, route)
|
||||||
assert.Equal(t, http.StatusOK, w.Code)
|
assert.Equal(t, http.StatusOK, w.Code)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -633,6 +634,6 @@ func TestRouteContextHoldsFullPath(t *testing.T) {
|
|||||||
assert.Equal(t, "", c.FullPath())
|
assert.Equal(t, "", c.FullPath())
|
||||||
})
|
})
|
||||||
|
|
||||||
w := performRequest(router, http.MethodGet, "/not-found")
|
w := PerformRequest(router, http.MethodGet, "/not-found")
|
||||||
assert.Equal(t, http.StatusNotFound, w.Code)
|
assert.Equal(t, http.StatusNotFound, w.Code)
|
||||||
}
|
}
|
||||||
|
4
tree.go
4
tree.go
@ -81,7 +81,7 @@ func longestCommonPrefix(a, b string) int {
|
|||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
// addChild will add a child node, keeping wildcards at the end
|
// addChild will add a child node, keeping wildcardChild at the end
|
||||||
func (n *node) addChild(child *node) {
|
func (n *node) addChild(child *node) {
|
||||||
if n.wildChild && len(n.children) > 0 {
|
if n.wildChild && len(n.children) > 0 {
|
||||||
wildcardChild := n.children[len(n.children)-1]
|
wildcardChild := n.children[len(n.children)-1]
|
||||||
@ -296,7 +296,7 @@ func (n *node) insertChild(path string, fullPath string, handlers HandlersChain)
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
// The wildcard name must not contain ':' and '*'
|
// The wildcard name must only contain one ':' or '*' character
|
||||||
if !valid {
|
if !valid {
|
||||||
panic("only one wildcard per path segment is allowed, has: '" +
|
panic("only one wildcard per path segment is allowed, has: '" +
|
||||||
wildcard + "' in path '" + fullPath + "'")
|
wildcard + "' in path '" + fullPath + "'")
|
||||||
|
@ -45,11 +45,11 @@ func TestWrap(t *testing.T) {
|
|||||||
fmt.Fprint(w, "hola!")
|
fmt.Fprint(w, "hola!")
|
||||||
}))
|
}))
|
||||||
|
|
||||||
w := performRequest(router, "POST", "/path")
|
w := PerformRequest(router, "POST", "/path")
|
||||||
assert.Equal(t, http.StatusInternalServerError, 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, http.StatusBadRequest, w.Code)
|
assert.Equal(t, http.StatusBadRequest, w.Code)
|
||||||
assert.Equal(t, "hola!", w.Body.String())
|
assert.Equal(t, "hola!", w.Body.String())
|
||||||
}
|
}
|
||||||
@ -119,13 +119,13 @@ func TestBindMiddleware(t *testing.T) {
|
|||||||
called = true
|
called = true
|
||||||
value = c.MustGet(BindKey).(*bindTestStruct)
|
value = c.MustGet(BindKey).(*bindTestStruct)
|
||||||
})
|
})
|
||||||
performRequest(router, "GET", "/?foo=hola&bar=10")
|
PerformRequest(router, "GET", "/?foo=hola&bar=10")
|
||||||
assert.True(t, called)
|
assert.True(t, called)
|
||||||
assert.Equal(t, "hola", value.Foo)
|
assert.Equal(t, "hola", value.Foo)
|
||||||
assert.Equal(t, 10, value.Bar)
|
assert.Equal(t, 10, value.Bar)
|
||||||
|
|
||||||
called = false
|
called = false
|
||||||
performRequest(router, "GET", "/?foo=hola&bar=1")
|
PerformRequest(router, "GET", "/?foo=hola&bar=1")
|
||||||
assert.False(t, called)
|
assert.False(t, called)
|
||||||
|
|
||||||
assert.Panics(t, func() {
|
assert.Panics(t, func() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user