Repository: gin-gonic/gin
Pull request #3372 (2022-10-24 22:08:59)

chore(deps): bump golangci/golangci-lint-action from 3.2.0 to 3.3.0
Bumps [golangci/golangci-lint-action](https://github.com/golangci/golangci-lint-action) from 3.2.0 to 3.3.0.
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/golangci/golangci-lint-action/commit/07db5389c99593f11ad7b44463c2d4233066a9b1"><code>07db538</code></a> build(deps): bump <code>@​actions/cache</code> from 3.0.4 to 3.0.5 (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/issues/586">#586</a>)</li>
<li><a href="https://github.com/golangci/golangci-lint-action/commit/328c000029c97b67afe4765e96eb71b1693f58bd"><code>328c000</code></a> build(deps-dev): bump <code>@​typescript-eslint/eslint-plugin</code> from 5.39.0 to 5.40.0 ...</li>
<li><a href="https://github.com/golangci/golangci-lint-action/commit/3a79f8d45a94d4190408a54a12b99d26d0dd9c89"><code>3a79f8d</code></a> build(deps-dev): bump <code>@​typescript-eslint/parser</code> from 5.39.0 to 5.40.0 (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/issues/584">#584</a>)</li>
<li><a href="https://github.com/golangci/golangci-lint-action/commit/43c645b597f45ef751d086ddd3781bae6bf4742e"><code>43c645b</code></a> build(deps-dev): bump eslint from 8.24.0 to 8.25.0 (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/issues/582">#582</a>)</li>
<li><a href="https://github.com/golangci/golangci-lint-action/commit/88e5fc63802322b98855637bc8054a58388df07e"><code>88e5fc6</code></a> build(deps-dev): bump <code>@​typescript-eslint/eslint-plugin</code> from 5.38.1 to 5.39.0 ...</li>
<li><a href="https://github.com/golangci/golangci-lint-action/commit/6191de56c96f33cd79d0af65c296f549fb91fffd"><code>6191de5</code></a> build(deps-dev): bump <code>@​typescript-eslint/parser</code> from 5.38.1 to 5.39.0 (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/issues/580">#580</a>)</li>
<li><a href="https://github.com/golangci/golangci-lint-action/commit/5423639e7b7afdedab2f2ee0957ae774f8b9a2f4"><code>5423639</code></a> build(deps): bump <code>@​actions/core</code> from 1.9.1 to 1.10.0 (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/issues/578">#578</a>)</li>
<li><a href="https://github.com/golangci/golangci-lint-action/commit/c225631afd7b06c93d93be71254d9efaf97ee1e1"><code>c225631</code></a> build(deps): bump <code>@​actions/github</code> from 5.1.0 to 5.1.1 (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/issues/576">#576</a>)</li>
<li><a href="https://github.com/golangci/golangci-lint-action/commit/b81d829cdbb72248aca6416b8a07be275afaca8f"><code>b81d829</code></a> build(deps-dev): bump typescript from 4.8.3 to 4.8.4 (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/issues/577">#577</a>)</li>
<li><a href="https://github.com/golangci/golangci-lint-action/commit/5b682fd40bc91e2ff296f10c5216c44220ed6e92"><code>5b682fd</code></a> build(deps-dev): bump <code>@​typescript-eslint/parser</code> from 5.38.0 to 5.38.1 (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/issues/575">#575</a>)</li>
<li>Additional commits viewable in <a href="https://github.com/golangci/golangci-lint-action/compare/v3.2.0...v3.3.0">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=golangci/golangci-lint-action&package-manager=github_actions&previous-version=3.2.0&new-version=3.3.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>

codecov[bot]: # [Codecov](https://codecov.io/gh/gin-gonic/gin/pull/3372?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) Report
> Merging [#3372](https://codecov.io/gh/gin-gonic/gin/pull/3372?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) (e3d7a78) into [master](https://codecov.io/gh/gin-gonic/gin/commit/51aea73ba0f125f6cacc3b4b695efdf21d9c634f?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) (51aea73) will **decrease** coverage by `0.09%`.
> The diff coverage is `n/a`.

```diff
@@            Coverage Diff             @@
##           master    #3372      +/-   ##
==========================================
- Coverage   98.27%   98.17%   -0.10%     
==========================================
  Files          42       42              
  Lines        3127     3127              
==========================================
- Hits         3073     3070       -3     
- Misses         40       42       +2     
- Partials       14       15       +1     
```

| Flag | Coverage Δ | |
|---|---|---|
|  | `98.17% <ø> (-0.10%)` | :arrow_down: |
| go-1.16 | `∅ <ø> (?)` | |
| go-1.17 | `98.17% <ø> (ø)` | |
| go-1.18 | `98.17% <ø> (ø)` | |
| go-1.19 | `?` | |
| macos-latest | `98.17% <ø> (-0.10%)` | :arrow_down: |
| ubuntu-latest | `98.17% <ø> (?)` | |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://codecov.io/gh/gin-gonic/gin/pull/3372?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) | Coverage Δ | |
|---|---|---|
| [context.go](https://codecov.io/gh/gin-gonic/gin/pull/3372/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic#diff-Y29udGV4dC5nbw==) | `97.45% <0.00%> (-0.51%)` | :arrow_down: |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic)


Patch:
diff --git a/.github/workflows/gin.yml b/.github/workflows/gin.yml
index 18b36d0..45ae932 100644
--- a/.github/workflows/gin.yml
+++ b/.github/workflows/gin.yml
@@ -22,7 +22,7 @@ jobs:
       - name: Checkout repository
         uses: actions/checkout@v3
       - name: Setup golangci-lint
-        uses: golangci/golangci-lint-action@v3.2.0
+        uses: golangci/golangci-lint-action@v3.3.0
         with:
           version: v1.48.0
           args: --verbose
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1bc51a8..a682c8c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -113,7 +113,7 @@
 * chore(performance): improve countParams ([#2378](https://github.com/gin-gonic/gin/pull/2378))
 * Remove some functions that have the same effect as the bytes package ([#2387](https://github.com/gin-gonic/gin/pull/2387))
 * update:SetMode function ([#2321](https://github.com/gin-gonic/gin/pull/2321))
-* remove a unused type SecureJSONPrefix ([#2391](https://github.com/gin-gonic/gin/pull/2391))
+* remove an unused type SecureJSONPrefix ([#2391](https://github.com/gin-gonic/gin/pull/2391))
 * Add a redirect sample for POST method ([#2389](https://github.com/gin-gonic/gin/pull/2389))
 * Add CustomRecovery builtin middleware ([#2322](https://github.com/gin-gonic/gin/pull/2322))
 * binding: avoid 2038 problem on 32-bit architectures ([#2450](https://github.com/gin-gonic/gin/pull/2450))
diff --git a/README.md b/README.md
index 960c66d..6445e97 100644
--- a/README.md
+++ b/README.md
@@ -87,7 +87,7 @@ Gin is a web framework written in Go (Golang). It features a martini-like API wi
 
 To install Gin package, you need to install Go and set your Go workspace first.
 
-1. You first need [Go](https://golang.org/) installed (**version 1.16+ is required**), then you can use the below Go command to install Gin.
+1. You first need [Go](https://go.dev/) installed (**version 1.16+ is required**), then you can use the below Go command to install Gin.
 
 ```sh
 go get -u github.com/gin-gonic/gin
@@ -293,7 +293,7 @@ func main() {
   router := gin.Default()
 
   // Query string parameters are parsed using the existing underlying request object.
-  // The request responds to a url matching:  /welcome?firstname=Jane&lastname=Doe
+  // The request responds to an url matching:  /welcome?firstname=Jane&lastname=Doe
   router.GET("/welcome", func(c *gin.Context) {
     firstname := c.DefaultQuery("firstname", "Guest")
     lastname := c.Query("lastname") // shortcut for c.Request.URL.Query().Get("lastname")
@@ -678,7 +678,7 @@ func main() {
 
 To bind a request body into a type, use model binding. We currently support binding of JSON, XML, YAML, TOML and standard form values (foo=bar&boo=baz).
 
-Gin uses [**go-playground/validator/v10**](https://github.com/go-playground/validator) for validation. Check the full docs on tags usage [here](https://godoc.org/github.com/go-playground/validator#hdr-Baked_In_Validators_and_Tags).
+Gin uses [**go-playground/validator/v10**](https://github.com/go-playground/validator) for validation. Check the full docs on tags usage [here](https://pkg.go.dev/github.com/go-playground/validator#hdr-Baked_In_Validators_and_Tags).
 
 Note that you need to set the corresponding binding tag on all fields you want to bind. For example, when binding from JSON, set `json:"fieldname"`.
 
@@ -693,7 +693,7 @@ Also, Gin provides two sets of methods for binding:
 
 When using the Bind-method, Gin tries to infer the binder depending on the Content-Type header. If you are sure what you are binding, you can use `MustBindWith` or `ShouldBindWith`.
 
-You can also specify that specific fields are required. If a field is decorated with `binding:"required"` and has a empty value when binding, an error will be returned.
+You can also specify that specific fields are required. If a field is decorated with `binding:"required"` and has an empty value when binding, an error will be returned.
 
 ```go
 // Binding from JSON
@@ -1820,7 +1820,7 @@ Alternatives:
 
 #### Manually
 
-In case you are using Go 1.8 or a later version, you may not need to use those libraries. Consider using `http.Server`'s built-in [Shutdown()](https://golang.org/pkg/net/http/#Server.Shutdown) method for graceful shutdowns. The example below describes its usage, and we've got more examples using gin [here](https://github.com/gin-gonic/examples/tree/master/graceful-shutdown).
+In case you are using Go 1.8 or a later version, you may not need to use those libraries. Consider using `http.Server`'s built-in [Shutdown()](https://pkg.go.dev/net/http#Server.Shutdown) method for graceful shutdowns. The example below describes its usage, and we've got more examples using gin [here](https://github.com/gin-gonic/examples/tree/master/graceful-shutdown).
 
 ```go
 // +build go1.8
@@ -2096,7 +2096,7 @@ func validate(obj interface{}) error {
 }
 
 // Now we can do this!!!
-// FormA is a external type that we can't modify it's tag
+// FormA is an external type that we can't modify it's tag
 type FormA struct {
   FieldA string `url:"field_a"`
 }
@@ -2116,7 +2116,7 @@ func ListHandler(s *Service) func(ctx *gin.Context) {
 
 ### http2 server push
 
-http.Pusher is supported only **go1.8+**. See the [golang blog](https://blog.golang.org/h2push) for detail information.
+http.Pusher is supported only **go1.8+**. See the [golang blog](https://go.dev/blog/h2push) for detail information.
 
 ```go
 package main
@@ -2364,7 +2364,7 @@ Awesome project lists using [Gin](https://github.com/gin-gonic/gin) web framewor
 * [gorush](https://github.com/appleboy/gorush): A push notification server written in Go.
 * [fnproject](https://github.com/fnproject/fn): The container native, cloud agnostic serverless platform.
 * [photoprism](https://github.com/photoprism/photoprism): Personal photo management powered by Go and Google TensorFlow.
-* [krakend](https://github.com/devopsfaith/krakend): Ultra performant API Gateway with middlewares.
+* [lura](https://github.com/luraproject/lura): Ultra performant API Gateway with middlewares.
 * [picfit](https://github.com/thoas/picfit): An image resizing server written in Go.
 * [brigade](https://github.com/brigadecore/brigade): Event-based Scripting for Kubernetes.
 * [dkron](https://github.com/distribworks/dkron): Distributed, fault tolerant job scheduling system.
diff --git a/gin.go b/gin.go
index a2e2e67..35159d0 100644
--- a/gin.go
+++ b/gin.go
@@ -203,7 +203,7 @@ func New() *Engine {
 	}
 	engine.RouterGroup.engine = engine
 	engine.pool.New = func() any {
-		return engine.allocateContext()
+		return engine.allocateContext(engine.maxParams)
 	}
 	return engine
 }
@@ -225,8 +225,8 @@ func (engine *Engine) Handler() http.Handler {
 	return h2c.NewHandler(engine, h2s)
 }
 
-func (engine *Engine) allocateContext() *Context {
-	v := make(Params, 0, engine.maxParams)
+func (engine *Engine) allocateContext(maxParams uint16) *Context {
+	v := make(Params, 0, maxParams)
 	skippedNodes := make([]skippedNode, 0, engine.maxSections)
 	return &Context{engine: engine, params: &v, skippedNodes: &skippedNodes}
 }
diff --git a/go.mod b/go.mod
index 1c64cf1..ebc1bd1 100644
--- a/go.mod
+++ b/go.mod
@@ -10,7 +10,7 @@ require (
 	github.com/json-iterator/go v1.1.12
 	github.com/mattn/go-isatty v0.0.16
 	github.com/pelletier/go-toml/v2 v2.0.2
-	github.com/stretchr/testify v1.8.0
+	github.com/stretchr/testify v1.8.1
 	github.com/ugorji/go/codec v1.2.7
 	golang.org/x/net v0.0.0-20221004154528-8021a29435af
 	google.golang.org/protobuf v1.28.1
diff --git a/go.sum b/go.sum
index 35bfd2e..acdf805 100644
--- a/go.sum
+++ b/go.sum
@@ -55,13 +55,15 @@ github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUA
 github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
-github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
 github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
 github.com/tidwall/gjson v1.13.0 h1:3TFY9yxOQShrvmjdM76K+jc66zJeT6D3/VFFYCGQf7M=
 github.com/tidwall/gjson v1.13.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
diff --git a/tree.go b/tree.go
index 956bf4d..3f34b8e 100644
--- a/tree.go
+++ b/tree.go
@@ -107,7 +107,8 @@ func countSections(path string) uint16 {
 type nodeType uint8
 
 const (
-	root nodeType = iota + 1
+	static nodeType = iota
+	root
 	param
 	catchAll
 )
@@ -173,6 +174,7 @@ walk:
 			child := node{
 				path:      n.path[i:],
 				wildChild: n.wildChild,
+				nType:     static,
 				indices:   n.indices,
 				children:  n.children,
 				handlers:  n.handlers,
@@ -604,6 +606,11 @@ walk: // Outer loop for walking the tree
 				return
 			}
 
+			if path == "/" && n.nType == static {
+				value.tsr = true
+				return
+			}
+
 			// No handle found. Check if a handle for this path + a
 			// trailing slash exists for trailing slash recommendation
 			for i, c := range []byte(n.indices) {


Test patch:
diff --git a/context_test.go b/context_test.go
index cc55cb0..85e0a61 100644
--- a/context_test.go
+++ b/context_test.go
@@ -146,7 +146,7 @@ func TestSaveUploadedCreateFailed(t *testing.T) {
 
 func TestContextReset(t *testing.T) {
 	router := New()
-	c := router.allocateContext()
+	c := router.allocateContext(0)
 	assert.Equal(t, c.engine, router)
 
 	c.index = 2
@@ -2354,3 +2354,17 @@ func TestContextAddParam(t *testing.T) {
 	assert.Equal(t, ok, true)
 	assert.Equal(t, value, v)
 }
+
+func TestCreateTestContextWithRouteParams(t *testing.T) {
+	w := httptest.NewRecorder()
+	engine := New()
+	engine.GET("/:action/:name", func(ctx *Context) {
+		ctx.String(http.StatusOK, "%s %s", ctx.Param("action"), ctx.Param("name"))
+	})
+	c := CreateTestContextOnly(w, engine)
+	c.Request, _ = http.NewRequest(http.MethodGet, "/hello/gin", nil)
+	engine.HandleContext(c)
+
+	assert.Equal(t, http.StatusOK, w.Code)
+	assert.Equal(t, "hello gin", w.Body.String())
+}
diff --git a/gin_test.go b/gin_test.go
index 4fac677..5ab2430 100644
--- a/gin_test.go
+++ b/gin_test.go
@@ -73,7 +73,7 @@ func TestLoadHTMLGlobDebugMode(t *testing.T) {
 
 	res, err := http.Get(fmt.Sprintf("%s/test", ts.URL))
 	if err != nil {
-		fmt.Println(err)
+		t.Error(err)
 	}
 
 	resp, _ := ioutil.ReadAll(res.Body)
@@ -83,7 +83,7 @@ func TestLoadHTMLGlobDebugMode(t *testing.T) {
 func TestH2c(t *testing.T) {
 	ln, err := net.Listen("tcp", "127.0.0.1:0")
 	if err != nil {
-		fmt.Println(err)
+		t.Error(err)
 	}
 	r := Default()
 	r.UseH2C = true
@@ -93,7 +93,7 @@ func TestH2c(t *testing.T) {
 	go func() {
 		err := http.Serve(ln, r.Handler())
 		if err != nil {
-			fmt.Println(err)
+			t.Log(err)
 		}
 	}()
 	defer ln.Close()
@@ -111,7 +111,7 @@ func TestH2c(t *testing.T) {
 
 	res, err := httpClient.Get(url)
 	if err != nil {
-		fmt.Println(err)
+		t.Error(err)
 	}
 
 	resp, _ := ioutil.ReadAll(res.Body)
@@ -131,7 +131,7 @@ func TestLoadHTMLGlobTestMode(t *testing.T) {
 
 	res, err := http.Get(fmt.Sprintf("%s/test", ts.URL))
 	if err != nil {
-		fmt.Println(err)
+		t.Error(err)
 	}
 
 	resp, _ := ioutil.ReadAll(res.Body)
@@ -151,7 +151,7 @@ func TestLoadHTMLGlobReleaseMode(t *testing.T) {
 
 	res, err := http.Get(fmt.Sprintf("%s/test", ts.URL))
 	if err != nil {
-		fmt.Println(err)
+		t.Error(err)
 	}
 
 	resp, _ := ioutil.ReadAll(res.Body)
@@ -178,7 +178,7 @@ func TestLoadHTMLGlobUsingTLS(t *testing.T) {
 	client := &http.Client{Transport: tr}
 	res, err := client.Get(fmt.Sprintf("%s/test", ts.URL))
 	if err != nil {
-		fmt.Println(err)
+		t.Error(err)
 	}
 
 	resp, _ := ioutil.ReadAll(res.Body)
@@ -198,7 +198,7 @@ func TestLoadHTMLGlobFromFuncMap(t *testing.T) {
 
 	res, err := http.Get(fmt.Sprintf("%s/raw", ts.URL))
 	if err != nil {
-		fmt.Println(err)
+		t.Error(err)
 	}
 
 	resp, _ := ioutil.ReadAll(res.Body)
@@ -229,7 +229,7 @@ func TestLoadHTMLFilesTestMode(t *testing.T) {
 
 	res, err := http.Get(fmt.Sprintf("%s/test", ts.URL))
 	if err != nil {
-		fmt.Println(err)
+		t.Error(err)
 	}
 
 	resp, _ := ioutil.ReadAll(res.Body)
@@ -249,7 +249,7 @@ func TestLoadHTMLFilesDebugMode(t *testing.T) {
 
 	res, err := http.Get(fmt.Sprintf("%s/test", ts.URL))
 	if err != nil {
-		fmt.Println(err)
+		t.Error(err)
 	}
 
 	resp, _ := ioutil.ReadAll(res.Body)
@@ -269,7 +269,7 @@ func TestLoadHTMLFilesReleaseMode(t *testing.T) {
 
 	res, err := http.Get(fmt.Sprintf("%s/test", ts.URL))
 	if err != nil {
-		fmt.Println(err)
+		t.Error(err)
 	}
 
 	resp, _ := ioutil.ReadAll(res.Body)
@@ -296,7 +296,7 @@ func TestLoadHTMLFilesUsingTLS(t *testing.T) {
 	client := &http.Client{Transport: tr}
 	res, err := client.Get(fmt.Sprintf("%s/test", ts.URL))
 	if err != nil {
-		fmt.Println(err)
+		t.Error(err)
 	}
 
 	resp, _ := ioutil.ReadAll(res.Body)
@@ -316,7 +316,7 @@ func TestLoadHTMLFilesFuncMap(t *testing.T) {
 
 	res, err := http.Get(fmt.Sprintf("%s/raw", ts.URL))
 	if err != nil {
-		fmt.Println(err)
+		t.Error(err)
 	}
 
 	resp, _ := ioutil.ReadAll(res.Body)
diff --git a/test_helpers.go b/test_helpers.go
index b3be93b..7508c5c 100644
--- a/test_helpers.go
+++ b/test_helpers.go
@@ -9,7 +9,15 @@ import "net/http"
 // 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 = r.allocateContext(0)
+	c.reset()
+	c.writermem.reset(w)
+	return
+}
+
+// CreateTestContextOnly returns a fresh context base on the engine for testing purposes
+func CreateTestContextOnly(w http.ResponseWriter, r *Engine) (c *Context) {
+	c = r.allocateContext(r.maxParams)
 	c.reset()
 	c.writermem.reset(w)
 	return
diff --git a/tree_test.go b/tree_test.go
index 085b580..2005738 100644
--- a/tree_test.go
+++ b/tree_test.go
@@ -684,6 +684,26 @@ func TestTreeRootTrailingSlashRedirect(t *testing.T) {
 	}
 }
 
+func TestRedirectTrailingSlash(t *testing.T) {
+	var data = []struct {
+		path string
+	}{
+		{"/hello/:name"},
+		{"/hello/:name/123"},
+		{"/hello/:name/234"},
+	}
+
+	node := &node{}
+	for _, item := range data {
+		node.addRoute(item.path, fakeHandler("test"))
+	}
+
+	value := node.getValue("/hello/abx/", nil, getSkippedNodes(), false)
+	if value.tsr != true {
+		t.Fatalf("want true, is false")
+	}
+}
+
 func TestTreeFindCaseInsensitivePath(t *testing.T) {
 	tree := &node{}