Repository: gin-gonic/gin
Pull request #3855 (2024-02-26 06:04:00)

chore(refactor): modify interface check way
Interface checks: [go.dev/doc/effective_go#blank_implements](https://go.dev/doc/effective_go#blank_implements)

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/gin-gonic/gin/pull/3855?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 99.36%. Comparing base [(`3dc1cd6`)](https://app.codecov.io/gh/gin-gonic/gin/commit/3dc1cd6572b4e3a0cd170a15debe546c2c72294f?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) to head [(`9da7cbc`)](https://app.codecov.io/gh/gin-gonic/gin/pull/3855?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic).
> Report is 6 commits behind head on master.


<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##           master    #3855      +/-   ##
==========================================
+ Coverage   99.21%   99.36%   +0.15%     
==========================================
  Files          42       43       +1     
  Lines        3182     2676     -506     
==========================================
- Hits         3157     2659     -498     
+ Misses         17        9       -8     
  Partials        8        8              
```

| [Flag](https://app.codecov.io/gh/gin-gonic/gin/pull/3855/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) | Coverage Δ | |
|---|---|---|
| [](https://app.codecov.io/gh/gin-gonic/gin/pull/3855/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) | `?` | |
| [-race](https://app.codecov.io/gh/gin-gonic/gin/pull/3855/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) | `∅ <ø> (?)` | |
| [-tags "sonic avx"](https://app.codecov.io/gh/gin-gonic/gin/pull/3855/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) | `99.35% <ø> (?)` | |
| [-tags go_json](https://app.codecov.io/gh/gin-gonic/gin/pull/3855/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) | `99.35% <ø> (?)` | |
| [-tags nomsgpack](https://app.codecov.io/gh/gin-gonic/gin/pull/3855/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) | `99.35% <ø> (?)` | |
| [go-1.18](https://app.codecov.io/gh/gin-gonic/gin/pull/3855/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) | `99.28% <ø> (+0.16%)` | :arrow_up: |
| [go-1.19](https://app.codecov.io/gh/gin-gonic/gin/pull/3855/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) | `99.36% <ø> (+0.15%)` | :arrow_up: |
| [go-1.20](https://app.codecov.io/gh/gin-gonic/gin/pull/3855/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) | `99.35% <ø> (+0.14%)` | :arrow_up: |
| [go-1.21](https://app.codecov.io/gh/gin-gonic/gin/pull/3855/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) | `?` | |
| [macos-latest](https://app.codecov.io/gh/gin-gonic/gin/pull/3855/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) | `?` | |
| [ubuntu-latest](https://app.codecov.io/gh/gin-gonic/gin/pull/3855/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) | `99.36% <ø> (+0.15%)` | :arrow_up: |

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.


</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/gin-gonic/gin/pull/3855?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic).

demoManito: 
<img width="811" alt="image" src="https://github.com/gin-gonic/gin/assets/27986239/86c68f12-931d-468e-8fc6-3f07d5facda8">

The error reported by ci should have nothing to do with the modification.

Patch:
diff --git a/binding/binding.go b/binding/binding.go
index 4094852..036b329 100644
--- a/binding/binding.go
+++ b/binding/binding.go
@@ -21,6 +21,7 @@ const (
 	MIMEMSGPACK           = "application/x-msgpack"
 	MIMEMSGPACK2          = "application/msgpack"
 	MIMEYAML              = "application/x-yaml"
+	MIMEYAML2             = "application/yaml"
 	MIMETOML              = "application/toml"
 )
 
@@ -102,7 +103,7 @@ func Default(method, contentType string) Binding {
 		return ProtoBuf
 	case MIMEMSGPACK, MIMEMSGPACK2:
 		return MsgPack
-	case MIMEYAML:
+	case MIMEYAML, MIMEYAML2:
 		return YAML
 	case MIMETOML:
 		return TOML
diff --git a/binding/binding_nomsgpack.go b/binding/binding_nomsgpack.go
index 93ad8ba..552a86b 100644
--- a/binding/binding_nomsgpack.go
+++ b/binding/binding_nomsgpack.go
@@ -19,6 +19,7 @@ const (
 	MIMEMultipartPOSTForm = "multipart/form-data"
 	MIMEPROTOBUF          = "application/x-protobuf"
 	MIMEYAML              = "application/x-yaml"
+	MIMEYAML2             = "application/yaml"
 	MIMETOML              = "application/toml"
 )
 
@@ -96,7 +97,7 @@ func Default(method, contentType string) Binding {
 		return XML
 	case MIMEPROTOBUF:
 		return ProtoBuf
-	case MIMEYAML:
+	case MIMEYAML, MIMEYAML2:
 		return YAML
 	case MIMEMultipartPOSTForm:
 		return FormMultipart
diff --git a/context.go b/context.go
index 420ff16..609827d 100644
--- a/context.go
+++ b/context.go
@@ -113,20 +113,25 @@ func (c *Context) Copy() *Context {
 	cp := Context{
 		writermem: c.writermem,
 		Request:   c.Request,
-		Params:    c.Params,
 		engine:    c.engine,
 	}
+
 	cp.writermem.ResponseWriter = nil
 	cp.Writer = &cp.writermem
 	cp.index = abortIndex
 	cp.handlers = nil
-	cp.Keys = map[string]any{}
-	for k, v := range c.Keys {
+	cp.fullPath = c.fullPath
+
+	cKeys := c.Keys
+	cp.Keys = make(map[string]any, len(cKeys))
+	for k, v := range cKeys {
 		cp.Keys[k] = v
 	}
-	paramCopy := make([]Param, len(cp.Params))
-	copy(paramCopy, cp.Params)
-	cp.Params = paramCopy
+
+	cParams := c.Params
+	cp.Params = make([]Param, len(cParams))
+	copy(cp.Params, cParams)
+
 	return &cp
 }
 
diff --git a/render/render.go b/render/render.go
index 7955000..4bdcfa2 100644
--- a/render/render.go
+++ b/render/render.go
@@ -15,22 +15,22 @@ type Render interface {
 }
 
 var (
-	_ Render     = JSON{}
-	_ Render     = IndentedJSON{}
-	_ Render     = SecureJSON{}
-	_ Render     = JsonpJSON{}
-	_ Render     = XML{}
-	_ Render     = String{}
-	_ Render     = Redirect{}
-	_ Render     = Data{}
-	_ Render     = HTML{}
-	_ HTMLRender = HTMLDebug{}
-	_ HTMLRender = HTMLProduction{}
-	_ Render     = YAML{}
-	_ Render     = Reader{}
-	_ Render     = AsciiJSON{}
-	_ Render     = ProtoBuf{}
-	_ Render     = TOML{}
+	_ Render     = (*JSON)(nil)
+	_ Render     = (*IndentedJSON)(nil)
+	_ Render     = (*SecureJSON)(nil)
+	_ Render     = (*JsonpJSON)(nil)
+	_ Render     = (*XML)(nil)
+	_ Render     = (*String)(nil)
+	_ Render     = (*Redirect)(nil)
+	_ Render     = (*Data)(nil)
+	_ Render     = (*HTML)(nil)
+	_ HTMLRender = (*HTMLDebug)(nil)
+	_ HTMLRender = (*HTMLProduction)(nil)
+	_ Render     = (*YAML)(nil)
+	_ Render     = (*Reader)(nil)
+	_ Render     = (*AsciiJSON)(nil)
+	_ Render     = (*ProtoBuf)(nil)
+	_ Render     = (*TOML)(nil)
 )
 
 func writeContentType(w http.ResponseWriter, value []string) {
diff --git a/render/yaml.go b/render/yaml.go
index fc927c1..042bb82 100644
--- a/render/yaml.go
+++ b/render/yaml.go
@@ -15,7 +15,7 @@ type YAML struct {
 	Data any
 }
 
-var yamlContentType = []string{"application/x-yaml; charset=utf-8"}
+var yamlContentType = []string{"application/yaml; charset=utf-8"}
 
 // Render (YAML) marshals the given interface object and writes data with custom ContentType.
 func (r YAML) Render(w http.ResponseWriter) error {


Test patch:
diff --git a/binding/binding_test.go b/binding/binding_test.go
index 9af4f88..feb8eed 100644
--- a/binding/binding_test.go
+++ b/binding/binding_test.go
@@ -164,6 +164,8 @@ func TestBindingDefault(t *testing.T) {
 
 	assert.Equal(t, YAML, Default("POST", MIMEYAML))
 	assert.Equal(t, YAML, Default("PUT", MIMEYAML))
+	assert.Equal(t, YAML, Default("POST", MIMEYAML2))
+	assert.Equal(t, YAML, Default("PUT", MIMEYAML2))
 
 	assert.Equal(t, TOML, Default("POST", MIMETOML))
 	assert.Equal(t, TOML, Default("PUT", MIMETOML))
diff --git a/context_test.go b/context_test.go
index 88165c0..ac766e2 100644
--- a/context_test.go
+++ b/context_test.go
@@ -324,6 +324,7 @@ func TestContextCopy(t *testing.T) {
 	c.handlers = HandlersChain{func(c *Context) {}}
 	c.Params = Params{Param{Key: "foo", Value: "bar"}}
 	c.Set("foo", "bar")
+	c.fullPath = "/hola"
 
 	cp := c.Copy()
 	assert.Nil(t, cp.handlers)
@@ -336,6 +337,7 @@ func TestContextCopy(t *testing.T) {
 	assert.Equal(t, cp.Params, c.Params)
 	cp.Set("foo", "notBar")
 	assert.False(t, cp.Keys["foo"] == c.Keys["foo"])
+	assert.Equal(t, cp.fullPath, c.fullPath)
 }
 
 func TestContextHandlerName(t *testing.T) {
@@ -1060,7 +1062,7 @@ func TestContextRenderUTF8Attachment(t *testing.T) {
 }
 
 // TestContextRenderYAML tests that the response is serialized as YAML
-// and Content-Type is set to application/x-yaml
+// and Content-Type is set to application/yaml
 func TestContextRenderYAML(t *testing.T) {
 	w := httptest.NewRecorder()
 	c, _ := CreateTestContext(w)
@@ -1069,7 +1071,7 @@ func TestContextRenderYAML(t *testing.T) {
 
 	assert.Equal(t, http.StatusCreated, w.Code)
 	assert.Equal(t, "foo: bar\n", w.Body.String())
-	assert.Equal(t, "application/x-yaml; charset=utf-8", w.Header().Get("Content-Type"))
+	assert.Equal(t, "application/yaml; charset=utf-8", w.Header().Get("Content-Type"))
 }
 
 // TestContextRenderTOML tests that the response is serialized as TOML
@@ -1217,7 +1219,7 @@ func TestContextNegotiationWithYAML(t *testing.T) {
 
 	assert.Equal(t, http.StatusOK, w.Code)
 	assert.Equal(t, "foo: bar\n", w.Body.String())
-	assert.Equal(t, "application/x-yaml; charset=utf-8", w.Header().Get("Content-Type"))
+	assert.Equal(t, "application/yaml; charset=utf-8", w.Header().Get("Content-Type"))
 }
 
 func TestContextNegotiationWithTOML(t *testing.T) {
diff --git a/render/render_test.go b/render/render_test.go
index c9db635..145f131 100644
--- a/render/render_test.go
+++ b/render/render_test.go
@@ -280,12 +280,12 @@ b:
 	d: [3, 4]
 	`
 	(YAML{data}).WriteContentType(w)
-	assert.Equal(t, "application/x-yaml; charset=utf-8", w.Header().Get("Content-Type"))
+	assert.Equal(t, "application/yaml; charset=utf-8", w.Header().Get("Content-Type"))
 
 	err := (YAML{data}).Render(w)
 	assert.NoError(t, err)
 	assert.Equal(t, "|4-\n    a : Easy!\n    b:\n    \tc: 2\n    \td: [3, 4]\n    \t\n", w.Body.String())
-	assert.Equal(t, "application/x-yaml; charset=utf-8", w.Header().Get("Content-Type"))
+	assert.Equal(t, "application/yaml; charset=utf-8", w.Header().Get("Content-Type"))
 }
 
 type fail struct{}
diff --git a/routes_test.go b/routes_test.go
index a0ff695..73f393e 100644
--- a/routes_test.go
+++ b/routes_test.go
@@ -180,58 +180,58 @@ func TestRouteRedirectTrailingSlash(t *testing.T) {
 
 	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, 301, w.Code)
+	assert.Equal(t, http.StatusMovedPermanently, w.Code)
 
 	w = PerformRequest(router, http.MethodGet, "/path2/", header{Key: "X-Forwarded-Prefix", Value: "/api/"})
-	assert.Equal(t, 200, w.Code)
+	assert.Equal(t, http.StatusOK, w.Code)
 
 	w = PerformRequest(router, http.MethodGet, "/path/", header{Key: "X-Forwarded-Prefix", Value: "../../api#?"})
 	assert.Equal(t, "/api/path", w.Header().Get("Location"))
-	assert.Equal(t, 301, w.Code)
+	assert.Equal(t, http.StatusMovedPermanently, w.Code)
 
 	w = PerformRequest(router, http.MethodGet, "/path/", header{Key: "X-Forwarded-Prefix", Value: "../../api"})
 	assert.Equal(t, "/api/path", w.Header().Get("Location"))
-	assert.Equal(t, 301, w.Code)
+	assert.Equal(t, http.StatusMovedPermanently, w.Code)
 
 	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, 301, w.Code)
+	assert.Equal(t, http.StatusMovedPermanently, w.Code)
 
 	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, 301, w.Code)
+	assert.Equal(t, http.StatusMovedPermanently, w.Code)
 
 	w = PerformRequest(router, http.MethodGet, "/path/", header{Key: "X-Forwarded-Prefix", Value: "api/../../"})
 	assert.Equal(t, "//path", w.Header().Get("Location"))
-	assert.Equal(t, 301, w.Code)
+	assert.Equal(t, http.StatusMovedPermanently, w.Code)
 
 	w = PerformRequest(router, http.MethodGet, "/path/", header{Key: "X-Forwarded-Prefix", Value: "api/../../../"})
 	assert.Equal(t, "/path", w.Header().Get("Location"))
-	assert.Equal(t, 301, w.Code)
+	assert.Equal(t, http.StatusMovedPermanently, w.Code)
 
 	w = PerformRequest(router, http.MethodGet, "/path2", header{Key: "X-Forwarded-Prefix", Value: "../../gin-gonic.com"})
 	assert.Equal(t, "/gin-goniccom/path2/", w.Header().Get("Location"))
-	assert.Equal(t, 301, w.Code)
+	assert.Equal(t, http.StatusMovedPermanently, w.Code)
 
 	w = PerformRequest(router, http.MethodGet, "/path2", header{Key: "X-Forwarded-Prefix", Value: "/../../gin-gonic.com"})
 	assert.Equal(t, "/gin-goniccom/path2/", w.Header().Get("Location"))
-	assert.Equal(t, 301, w.Code)
+	assert.Equal(t, http.StatusMovedPermanently, w.Code)
 
 	w = PerformRequest(router, http.MethodGet, "/path/", header{Key: "X-Forwarded-Prefix", Value: "https://gin-gonic.com/#"})
 	assert.Equal(t, "https/gin-goniccom/https/gin-goniccom/path", w.Header().Get("Location"))
-	assert.Equal(t, 301, w.Code)
+	assert.Equal(t, http.StatusMovedPermanently, w.Code)
 
 	w = PerformRequest(router, http.MethodGet, "/path/", header{Key: "X-Forwarded-Prefix", Value: "#api"})
 	assert.Equal(t, "api/api/path", w.Header().Get("Location"))
-	assert.Equal(t, 301, w.Code)
+	assert.Equal(t, http.StatusMovedPermanently, w.Code)
 
 	w = PerformRequest(router, http.MethodGet, "/path/", header{Key: "X-Forwarded-Prefix", Value: "/nor-mal/#?a=1"})
 	assert.Equal(t, "/nor-mal/a1/path", w.Header().Get("Location"))
-	assert.Equal(t, 301, w.Code)
+	assert.Equal(t, http.StatusMovedPermanently, w.Code)
 
 	w = PerformRequest(router, http.MethodGet, "/path/", header{Key: "X-Forwarded-Prefix", Value: "/nor-mal/%2e%2e/"})
 	assert.Equal(t, "/nor-mal/2e2e/path", w.Header().Get("Location"))
-	assert.Equal(t, 301, w.Code)
+	assert.Equal(t, http.StatusMovedPermanently, w.Code)
 
 	router.RedirectTrailingSlash = false
 
@@ -339,7 +339,7 @@ func TestRouteParamsByNameWithExtraSlash(t *testing.T) {
 
 // TestRouteParamsNotEmpty tests that context parameters will be set
 // even if a route with params/wildcards is registered after the context
-// initialisation (which happened in a previous requets).
+// initialisation (which happened in a previous requests).
 func TestRouteParamsNotEmpty(t *testing.T) {
 	name := ""
 	lastName := ""
@@ -619,11 +619,11 @@ func TestRouterNotFound(t *testing.T) {
 	router = New()
 	router.NoRoute(func(c *Context) {
 		if c.Request.RequestURI == "/login" {
-			c.String(200, "login")
+			c.String(http.StatusOK, "login")
 		}
 	})
 	router.GET("/logout", func(c *Context) {
-		c.String(200, "logout")
+		c.String(http.StatusOK, "logout")
 	})
 	w = PerformRequest(router, http.MethodGet, "/login")
 	assert.Equal(t, "login", w.Body.String())
@@ -635,7 +635,7 @@ func TestRouterStaticFSNotFound(t *testing.T) {
 	router := New()
 	router.StaticFS("/", http.FileSystem(http.Dir("/thisreallydoesntexist/")))
 	router.NoRoute(func(c *Context) {
-		c.String(404, "non existent")
+		c.String(http.StatusNotFound, "non existent")
 	})
 
 	w := PerformRequest(router, http.MethodGet, "/nonexistent")
@@ -718,12 +718,12 @@ func TestRouteRawPathNoUnescape(t *testing.T) {
 func TestRouteServeErrorWithWriteHeader(t *testing.T) {
 	route := New()
 	route.Use(func(c *Context) {
-		c.Status(421)
+		c.Status(http.StatusMisdirectedRequest)
 		c.Next()
 	})
 
 	w := PerformRequest(route, http.MethodGet, "/NotFound")
-	assert.Equal(t, 421, w.Code)
+	assert.Equal(t, http.StatusMisdirectedRequest, w.Code)
 	assert.Equal(t, 0, w.Body.Len())
 }