Skip to content

Use the gin.CreateTestContext in test, could not get the param in the route. #2778

@Hanaasagi

Description

@Hanaasagi
  • With issues:
    • Use the search tool before opening a new issue.
    • Please provide source code and commit sha if you found a bug.
    • Review existing issues and provide feedback or react to them.

Description

#2755 only fixes the slice bounds out of range panic. Route params are not be handled correctly in test context. I can explain what happened.

When call CreateTestContext, it will call New function to create a Engine. The maxParams will be the default value 0.

gin/test_helpers.go

Lines 9 to 16 in 9c27053

// CreateTestContext returns a fresh engine and context for testing purposes
func CreateTestContext(w http.ResponseWriter) (c *Context, r *Engine) {
r = New()
c = r.allocateContext()
c.reset()
c.writermem.reset(w)
return
}

Then allocateContext init the Params. The cap and len are both 0. params is the reference of Params.

gin/gin.go

Lines 202 to 205 in 9c27053

func (engine *Engine) allocateContext() *Context {
v := make(Params, 0, engine.maxParams)
return &Context{engine: engine, params: &v}
}

Even if we add a route, it only incrs the maxParams value, it has not effect on the Context we created by CreateTestContext before. The condition will always be false.

gin/tree.go

Lines 462 to 479 in 9c27053

if params != nil && cap(*params) > 0 {
if value.params == nil {
value.params = params
}
// Expand slice within preallocated capacity
i := len(*value.params)
*value.params = (*value.params)[:i+1]
val := path[:end]
if unescape {
if v, err := url.QueryUnescape(val); err == nil {
val = v
}
}
(*value.params)[i] = Param{
Key: n.path[1:],
Value: val,
}
}

How to reproduce

package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"

	"github.com/gin-gonic/gin"
)

func main() {
	w := httptest.NewRecorder()
	ctx, engine := gin.CreateTestContext(w)
	engine.GET("/hello/:name", func(ctx *gin.Context) {
		fmt.Printf("Param name is %s\n", ctx.Param("name"))
		ctx.String(http.StatusOK, "Hello %s", ctx.Param("name"))
	})
	var err error
	ctx.Request, err = http.NewRequest(http.MethodGet, "/hello/world", nil)
	if err != nil {
		panic(err)
	}
	engine.HandleContext(ctx)
}

Expectations

Get following output after running the code.

[GIN-debug] GET    /hello/:name              --> main.main.func1 (1 handlers)
Param name is world

Actual result

[GIN-debug] GET    /hello/:name              --> main.main.func1 (1 handlers)
Param name is 

ctx.Param("name") returns a empty string.

Environment

  • go version: go version go1.16 darwin/amd64
  • gin version (or commit ref): v1.7.2-0.20210704023713-9c27053243cb
  • operating system: macOs Big Sur 11.4, Darwin Kernel Version 20.5.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions