diff --git a/.github/workflows/gin.yml b/.github/workflows/gin.yml index 54185a0a..6f0f7c11 100644 --- a/.github/workflows/gin.yml +++ b/.github/workflows/gin.yml @@ -24,9 +24,9 @@ jobs: with: go-version: "^1" - name: Setup golangci-lint - uses: golangci/golangci-lint-action@v6 + uses: golangci/golangci-lint-action@v8 with: - version: v1.61.0 + version: v2.1.6 args: --verbose test: needs: lint diff --git a/.golangci.yml b/.golangci.yml index 925e1306..d9a60ce2 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,16 +1,11 @@ -run: - timeout: 5m +version: "2" linters: enable: - asciicheck + - copyloopvar - dogsled - durationcheck - - errcheck - errorlint - - copyloopvar - - gci - - gofmt - - goimports - gosec - misspell - nakedret @@ -21,51 +16,66 @@ linters: - testifylint - usestdlibvars - wastedassign - -linters-settings: - gosec: - # To select a subset of rules to run. - # Available rules: https://github.com/securego/gosec#available-rules - # Default: [] - means include all rules - includes: - - G102 - - G106 - - G108 - - G109 - - G111 - - G112 - - G201 - - G203 - perfsprint: - err-error: true - errorf: true - int-conversion: true - sprintf1: true - strconcat: true - testifylint: - enable-all: true - -issues: - exclude-rules: - - linters: - - structcheck - - unused - text: "`data` is unused" - - linters: - - staticcheck - text: "SA1019:" - - linters: - - revive - text: "var-naming:" - - linters: - - revive - text: "exported:" - - path: _test\.go - linters: - - gosec # security is not make sense in tests - - linters: - - revive - path: _test\.go - - path: gin.go - linters: - - gci + settings: + gosec: + includes: + - G102 + - G106 + - G108 + - G109 + - G111 + - G112 + - G201 + - G203 + perfsprint: + int-conversion: true + err-error: true + errorf: true + sprintf1: true + strconcat: true + testifylint: + enable-all: true + exclusions: + generated: lax + presets: + - comments + - common-false-positives + - legacy + - std-error-handling + rules: + - linters: + - structcheck + - unused + text: '`data` is unused' + - linters: + - staticcheck + text: 'SA1019:' + - linters: + - revive + text: 'var-naming:' + - linters: + - revive + text: 'exported:' + - linters: + - gosec + path: _test\.go + - linters: + - revive + path: _test\.go + paths: + - third_party$ + - builtin$ + - examples$ +formatters: + enable: + - gci + - gofmt + - gofumpt + - goimports + exclusions: + generated: lax + paths: + - third_party$ + - builtin$ + - examples$ + - gin.go diff --git a/binding/binding_test.go b/binding/binding_test.go index bdab3694..07619ebf 100644 --- a/binding/binding_test.go +++ b/binding/binding_test.go @@ -51,8 +51,6 @@ type FooBarFileStruct struct { type FooBarFileFailStruct struct { FooBarStruct File *multipart.FileHeader `invalid_name:"file" binding:"required"` - // for unexport test - data *multipart.FileHeader `form:"data" binding:"required"` } type FooDefaultBarStruct struct { @@ -1063,7 +1061,7 @@ func testFormBindingInvalidName(t *testing.T, method, path, badPath, body, badBo } err := b.Bind(req, &obj) require.NoError(t, err) - assert.Equal(t, "", obj.TestName) + assert.Empty(t, obj.TestName) obj = InvalidNameType{} req = requestWithBody(method, badPath, badBody) @@ -1318,7 +1316,7 @@ func testBodyBindingFail(t *testing.T, b Binding, name, path, badPath, body, bad req := requestWithBody(http.MethodPost, path, body) err := b.Bind(req, &obj) require.Error(t, err) - assert.Equal(t, "", obj.Foo) + assert.Empty(t, obj.Foo) obj = FooStruct{} req = requestWithBody(http.MethodPost, badPath, badBody) diff --git a/binding/default_validator_test.go b/binding/default_validator_test.go index df7742b7..fc819eb4 100644 --- a/binding/default_validator_test.go +++ b/binding/default_validator_test.go @@ -18,14 +18,16 @@ func TestSliceValidationError(t *testing.T) { {"has nil elements", SliceValidationError{errors.New("test error"), nil}, "[0]: test error"}, {"has zero elements", SliceValidationError{}, ""}, {"has one element", SliceValidationError{errors.New("test one error")}, "[0]: test one error"}, - {"has two elements", + { + "has two elements", SliceValidationError{ errors.New("first error"), errors.New("second error"), }, "[0]: first error\n[1]: second error", }, - {"has many elements", + { + "has many elements", SliceValidationError{ errors.New("first error"), errors.New("second error"), diff --git a/binding/form.go b/binding/form.go index b17352ba..06732e97 100644 --- a/binding/form.go +++ b/binding/form.go @@ -11,9 +11,11 @@ import ( const defaultMemory = 32 << 20 -type formBinding struct{} -type formPostBinding struct{} -type formMultipartBinding struct{} +type ( + formBinding struct{} + formPostBinding struct{} + formMultipartBinding struct{} +) func (formBinding) Name() string { return "form" diff --git a/binding/form_mapping_test.go b/binding/form_mapping_test.go index 45cd9297..9b6e1572 100644 --- a/binding/form_mapping_test.go +++ b/binding/form_mapping_test.go @@ -515,9 +515,9 @@ func TestMappingCustomStructTypeWithFormTag(t *testing.T) { err := mappingByPtr(&s, formSource{"data": {`file:/foo:happiness`}}, "form") require.NoError(t, err) - assert.EqualValues(t, "file", s.FileData.Protocol) - assert.EqualValues(t, "/foo", s.FileData.Path) - assert.EqualValues(t, "happiness", s.FileData.Name) + assert.Equal(t, "file", s.FileData.Protocol) + assert.Equal(t, "/foo", s.FileData.Path) + assert.Equal(t, "happiness", s.FileData.Name) } func TestMappingCustomStructTypeWithURITag(t *testing.T) { @@ -527,9 +527,9 @@ func TestMappingCustomStructTypeWithURITag(t *testing.T) { err := mappingByPtr(&s, formSource{"data": {`file:/foo:happiness`}}, "uri") require.NoError(t, err) - assert.EqualValues(t, "file", s.FileData.Protocol) - assert.EqualValues(t, "/foo", s.FileData.Path) - assert.EqualValues(t, "happiness", s.FileData.Name) + assert.Equal(t, "file", s.FileData.Protocol) + assert.Equal(t, "/foo", s.FileData.Path) + assert.Equal(t, "happiness", s.FileData.Name) } func TestMappingCustomPointerStructTypeWithFormTag(t *testing.T) { @@ -539,9 +539,9 @@ func TestMappingCustomPointerStructTypeWithFormTag(t *testing.T) { err := mappingByPtr(&s, formSource{"data": {`file:/foo:happiness`}}, "form") require.NoError(t, err) - assert.EqualValues(t, "file", s.FileData.Protocol) - assert.EqualValues(t, "/foo", s.FileData.Path) - assert.EqualValues(t, "happiness", s.FileData.Name) + assert.Equal(t, "file", s.FileData.Protocol) + assert.Equal(t, "/foo", s.FileData.Path) + assert.Equal(t, "happiness", s.FileData.Name) } func TestMappingCustomPointerStructTypeWithURITag(t *testing.T) { @@ -551,9 +551,9 @@ func TestMappingCustomPointerStructTypeWithURITag(t *testing.T) { err := mappingByPtr(&s, formSource{"data": {`file:/foo:happiness`}}, "uri") require.NoError(t, err) - assert.EqualValues(t, "file", s.FileData.Protocol) - assert.EqualValues(t, "/foo", s.FileData.Path) - assert.EqualValues(t, "happiness", s.FileData.Name) + assert.Equal(t, "file", s.FileData.Protocol) + assert.Equal(t, "/foo", s.FileData.Path) + assert.Equal(t, "happiness", s.FileData.Name) } type customPath []string @@ -576,8 +576,8 @@ func TestMappingCustomSliceUri(t *testing.T) { err := mappingByPtr(&s, formSource{"path": {`bar/foo`}}, "uri") require.NoError(t, err) - assert.EqualValues(t, "bar", s.FileData[0]) - assert.EqualValues(t, "foo", s.FileData[1]) + assert.Equal(t, "bar", s.FileData[0]) + assert.Equal(t, "foo", s.FileData[1]) } func TestMappingCustomSliceForm(t *testing.T) { @@ -587,8 +587,8 @@ func TestMappingCustomSliceForm(t *testing.T) { err := mappingByPtr(&s, formSource{"path": {`bar/foo`}}, "form") require.NoError(t, err) - assert.EqualValues(t, "bar", s.FileData[0]) - assert.EqualValues(t, "foo", s.FileData[1]) + assert.Equal(t, "bar", s.FileData[0]) + assert.Equal(t, "foo", s.FileData[1]) } type objectID [12]byte @@ -627,7 +627,7 @@ func TestMappingCustomArrayUri(t *testing.T) { require.NoError(t, err) expected, _ := convertTo(val) - assert.EqualValues(t, expected, s.FileData) + assert.Equal(t, expected, s.FileData) } func TestMappingCustomArrayForm(t *testing.T) { @@ -639,5 +639,5 @@ func TestMappingCustomArrayForm(t *testing.T) { require.NoError(t, err) expected, _ := convertTo(val) - assert.EqualValues(t, expected, s.FileData) + assert.Equal(t, expected, s.FileData) } diff --git a/binding/header.go b/binding/header.go index 03bc78da..6ed8c0c5 100644 --- a/binding/header.go +++ b/binding/header.go @@ -17,7 +17,6 @@ func (headerBinding) Name() string { } func (headerBinding) Bind(req *http.Request, obj any) error { - if err := mapHeader(obj, req.Header); err != nil { return err } diff --git a/binding/validate_test.go b/binding/validate_test.go index c9bbe601..792f64c4 100644 --- a/binding/validate_test.go +++ b/binding/validate_test.go @@ -158,16 +158,16 @@ type structNoValidationPointer struct { } func TestValidateNoValidationPointers(t *testing.T) { - //origin := createNoValidation_values() - //test := createNoValidation_values() + // origin := createNoValidation_values() + // test := createNoValidation_values() empty := structNoValidationPointer{} - //assert.Nil(t, validate(test)) - //assert.Nil(t, validate(&test)) + // assert.Nil(t, validate(test)) + // assert.Nil(t, validate(&test)) require.NoError(t, validate(empty)) require.NoError(t, validate(&empty)) - //assert.Equal(t, origin, test) + // assert.Equal(t, origin, test) } type Object map[string]any @@ -198,7 +198,7 @@ type structModifyValidation struct { } func toZero(sl validator.StructLevel) { - var s *structModifyValidation = sl.Top().Interface().(*structModifyValidation) + s := sl.Top().Interface().(*structModifyValidation) s.Integer = 0 } @@ -249,5 +249,5 @@ func TestValidatorEngine(t *testing.T) { // Check that we got back non-nil errs require.Error(t, errs) // Check that the error matches expectation - require.Error(t, errs, "", "", "notone") + require.Error(t, errs, "notone") } diff --git a/binding/xml.go b/binding/xml.go index a70f4ad3..acd6f942 100644 --- a/binding/xml.go +++ b/binding/xml.go @@ -24,6 +24,7 @@ func (xmlBinding) Bind(req *http.Request, obj any) error { func (xmlBinding) BindBody(body []byte, obj any) error { return decodeXML(bytes.NewReader(body), obj) } + func decodeXML(r io.Reader, obj any) error { decoder := xml.NewDecoder(r) if err := decoder.Decode(obj); err != nil { diff --git a/context_test.go b/context_test.go index ebcd08d4..084bae5d 100644 --- a/context_test.go +++ b/context_test.go @@ -918,7 +918,7 @@ func TestContextRenderJSON(t *testing.T) { c.JSON(http.StatusCreated, H{"foo": "bar", "html": ""}) assert.Equal(t, http.StatusCreated, w.Code) - assert.Equal(t, "{\"foo\":\"bar\",\"html\":\"\\u003cb\\u003e\"}", w.Body.String()) + assert.JSONEq(t, "{\"foo\":\"bar\",\"html\":\"\\u003cb\\u003e\"}", w.Body.String()) assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type")) } @@ -946,7 +946,7 @@ func TestContextRenderJSONPWithoutCallback(t *testing.T) { c.JSONP(http.StatusCreated, H{"foo": "bar"}) assert.Equal(t, http.StatusCreated, w.Code) - assert.Equal(t, "{\"foo\":\"bar\"}", w.Body.String()) + assert.JSONEq(t, "{\"foo\":\"bar\"}", w.Body.String()) assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type")) } @@ -972,7 +972,7 @@ func TestContextRenderAPIJSON(t *testing.T) { c.JSON(http.StatusCreated, H{"foo": "bar"}) assert.Equal(t, http.StatusCreated, w.Code) - assert.Equal(t, "{\"foo\":\"bar\"}", w.Body.String()) + assert.JSONEq(t, "{\"foo\":\"bar\"}", w.Body.String()) assert.Equal(t, "application/vnd.api+json", w.Header().Get("Content-Type")) } @@ -998,7 +998,7 @@ func TestContextRenderIndentedJSON(t *testing.T) { c.IndentedJSON(http.StatusCreated, H{"foo": "bar", "bar": "foo", "nested": H{"foo": "bar"}}) assert.Equal(t, http.StatusCreated, w.Code) - assert.Equal(t, "{\n \"bar\": \"foo\",\n \"foo\": \"bar\",\n \"nested\": {\n \"foo\": \"bar\"\n }\n}", w.Body.String()) + assert.JSONEq(t, "{\n \"bar\": \"foo\",\n \"foo\": \"bar\",\n \"nested\": {\n \"foo\": \"bar\"\n }\n}", w.Body.String()) assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type")) } @@ -1059,7 +1059,7 @@ func TestContextRenderPureJSON(t *testing.T) { c, _ := CreateTestContext(w) c.PureJSON(http.StatusCreated, H{"foo": "bar", "html": ""}) assert.Equal(t, http.StatusCreated, w.Code) - assert.Equal(t, "{\"foo\":\"bar\",\"html\":\"\"}\n", w.Body.String()) + assert.JSONEq(t, "{\"foo\":\"bar\",\"html\":\"\"}\n", w.Body.String()) assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type")) } @@ -1233,7 +1233,7 @@ func TestContextRenderSSE(t *testing.T) { "bar": "foo", }) - assert.Equal(t, strings.Replace(w.Body.String(), " ", "", -1), strings.Replace("event:float\ndata:1.5\n\nid:123\ndata:text\n\nevent:chat\ndata:{\"bar\":\"foo\",\"foo\":\"bar\"}\n\n", " ", "", -1)) + assert.Equal(t, strings.ReplaceAll(w.Body.String(), " ", ""), strings.ReplaceAll("event:float\ndata:1.5\n\nid:123\ndata:text\n\nevent:chat\ndata:{\"bar\":\"foo\",\"foo\":\"bar\"}\n\n", " ", "")) } func TestContextRenderFile(t *testing.T) { @@ -1247,7 +1247,7 @@ func TestContextRenderFile(t *testing.T) { assert.Contains(t, w.Body.String(), "func New(opts ...OptionFunc) *Engine {") // Content-Type='text/plain; charset=utf-8' when go version <= 1.16, // else, Content-Type='text/x-go; charset=utf-8' - assert.NotEqual(t, "", w.Header().Get("Content-Type")) + assert.NotEmpty(t, w.Header().Get("Content-Type")) } func TestContextRenderFileFromFS(t *testing.T) { @@ -1261,7 +1261,7 @@ func TestContextRenderFileFromFS(t *testing.T) { assert.Contains(t, w.Body.String(), "func New(opts ...OptionFunc) *Engine {") // Content-Type='text/plain; charset=utf-8' when go version <= 1.16, // else, Content-Type='text/x-go; charset=utf-8' - assert.NotEqual(t, "", w.Header().Get("Content-Type")) + assert.NotEmpty(t, w.Header().Get("Content-Type")) assert.Equal(t, "/some/path", c.Request.URL.Path) } @@ -1432,7 +1432,7 @@ func TestContextNegotiationWithJSON(t *testing.T) { }) assert.Equal(t, http.StatusOK, w.Code) - assert.Equal(t, "{\"foo\":\"bar\"}", w.Body.String()) + assert.JSONEq(t, "{\"foo\":\"bar\"}", w.Body.String()) assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type")) } @@ -1518,7 +1518,7 @@ func TestContextNegotiationFormat(t *testing.T) { c.Request, _ = http.NewRequest(http.MethodPost, "", nil) assert.Panics(t, func() { c.NegotiateFormat() }) - assert.Equal(t, MIMEJSON, c.NegotiateFormat(MIMEJSON, MIMEXML)) + assert.Equal(t, MIMEJSON, c.NegotiateFormat(MIMEJSON, MIMEXML)) //nolint:testifylint assert.Equal(t, MIMEHTML, c.NegotiateFormat(MIMEHTML, MIMEJSON)) } @@ -1540,7 +1540,7 @@ func TestContextNegotiationFormatWithWildcardAccept(t *testing.T) { assert.Equal(t, "*/*", c.NegotiateFormat("*/*")) assert.Equal(t, "text/*", c.NegotiateFormat("text/*")) assert.Equal(t, "application/*", c.NegotiateFormat("application/*")) - assert.Equal(t, MIMEJSON, c.NegotiateFormat(MIMEJSON)) + assert.Equal(t, MIMEJSON, c.NegotiateFormat(MIMEJSON)) //nolint:testifylint assert.Equal(t, MIMEXML, c.NegotiateFormat(MIMEXML)) assert.Equal(t, MIMEHTML, c.NegotiateFormat(MIMEHTML)) @@ -1550,9 +1550,9 @@ func TestContextNegotiationFormatWithWildcardAccept(t *testing.T) { assert.Equal(t, "*/*", c.NegotiateFormat("*/*")) assert.Equal(t, "text/*", c.NegotiateFormat("text/*")) - assert.Equal(t, "", c.NegotiateFormat("application/*")) - assert.Equal(t, "", c.NegotiateFormat(MIMEJSON)) - assert.Equal(t, "", c.NegotiateFormat(MIMEXML)) + assert.Empty(t, c.NegotiateFormat("application/*")) + assert.Empty(t, c.NegotiateFormat(MIMEJSON)) + assert.Empty(t, c.NegotiateFormat(MIMEXML)) assert.Equal(t, MIMEHTML, c.NegotiateFormat(MIMEHTML)) } @@ -1564,9 +1564,9 @@ func TestContextNegotiationFormatCustom(t *testing.T) { c.Accepted = nil c.SetAccepted(MIMEJSON, MIMEXML) - assert.Equal(t, MIMEJSON, c.NegotiateFormat(MIMEJSON, MIMEXML)) + assert.Equal(t, MIMEJSON, c.NegotiateFormat(MIMEJSON, MIMEXML)) //nolint:testifylint assert.Equal(t, MIMEXML, c.NegotiateFormat(MIMEXML, MIMEHTML)) - assert.Equal(t, MIMEJSON, c.NegotiateFormat(MIMEJSON)) + assert.Equal(t, MIMEJSON, c.NegotiateFormat(MIMEJSON)) //nolint:testifylint } func TestContextNegotiationFormat2(t *testing.T) { @@ -1574,7 +1574,7 @@ func TestContextNegotiationFormat2(t *testing.T) { c.Request, _ = http.NewRequest(http.MethodPost, "/", nil) c.Request.Header.Add("Accept", "image/tiff-fx") - assert.Equal(t, "", c.NegotiateFormat("image/tiff")) + assert.Empty(t, c.NegotiateFormat("image/tiff")) } func TestContextIsAborted(t *testing.T) { @@ -1634,7 +1634,7 @@ func TestContextAbortWithStatusJSON(t *testing.T) { _, err := buf.ReadFrom(w.Body) require.NoError(t, err) jsonStringBody := buf.String() - assert.Equal(t, "{\"foo\":\"fooValue\",\"bar\":\"barValue\"}", jsonStringBody) + assert.JSONEq(t, "{\"foo\":\"fooValue\",\"bar\":\"barValue\"}", jsonStringBody) } func TestContextError(t *testing.T) { @@ -3076,7 +3076,7 @@ func TestInterceptedHeader(t *testing.T) { // Compared to this time, this is when the response headers will be flushed // As response is flushed on c.String, the Header cannot be set by the first // middleware. Assert this - assert.Equal(t, "", w.Result().Header.Get("X-Test")) + assert.Empty(t, w.Result().Header.Get("X-Test")) assert.Equal(t, "present", w.Result().Header.Get("X-Test-2")) } diff --git a/errors_test.go b/errors_test.go index 91ae9c92..85ed3dd5 100644 --- a/errors_test.go +++ b/errors_test.go @@ -34,7 +34,7 @@ func TestError(t *testing.T) { }, err.JSON()) jsonBytes, _ := json.Marshal(err) - assert.Equal(t, "{\"error\":\"test error\",\"meta\":\"some data\"}", string(jsonBytes)) + assert.JSONEq(t, "{\"error\":\"test error\",\"meta\":\"some data\"}", string(jsonBytes)) err.SetMeta(H{ //nolint: errcheck "status": "200", @@ -93,13 +93,13 @@ Error #03: third H{"error": "third", "status": "400"}, }, errs.JSON()) jsonBytes, _ := json.Marshal(errs) - assert.Equal(t, "[{\"error\":\"first\"},{\"error\":\"second\",\"meta\":\"some data\"},{\"error\":\"third\",\"status\":\"400\"}]", string(jsonBytes)) + assert.JSONEq(t, "[{\"error\":\"first\"},{\"error\":\"second\",\"meta\":\"some data\"},{\"error\":\"third\",\"status\":\"400\"}]", string(jsonBytes)) errs = errorMsgs{ {Err: errors.New("first"), Type: ErrorTypePrivate}, } assert.Equal(t, H{"error": "first"}, errs.JSON()) jsonBytes, _ = json.Marshal(errs) - assert.Equal(t, "{\"error\":\"first\"}", string(jsonBytes)) + assert.JSONEq(t, "{\"error\":\"first\"}", string(jsonBytes)) errs = errorMsgs{} assert.Nil(t, errs.Last()) diff --git a/fs.go b/fs.go index 51c3db86..ab18adb3 100644 --- a/fs.go +++ b/fs.go @@ -17,7 +17,6 @@ type OnlyFilesFS struct { // Open passes `Open` to the upstream implementation without `Readdir` functionality. func (o OnlyFilesFS) Open(name string) (http.File, error) { f, err := o.FileSystem.Open(name) - if err != nil { return nil, err } diff --git a/gin.go b/gin.go index f9813e1d..27eea83e 100644 --- a/gin.go +++ b/gin.go @@ -18,7 +18,6 @@ import ( "github.com/gin-gonic/gin/internal/bytesconv" filesystem "github.com/gin-gonic/gin/internal/fs" "github.com/gin-gonic/gin/render" - "github.com/quic-go/quic-go/http3" "golang.org/x/net/http2" "golang.org/x/net/http2/h2c" @@ -216,7 +215,7 @@ func New(opts ...OptionFunc) *Engine { trustedProxies: []string{"0.0.0.0/0", "::/0"}, trustedCIDRs: defaultTrustedCIDRs, } - engine.RouterGroup.engine = engine + engine.engine = engine engine.pool.New = func() any { return engine.allocateContext(engine.maxParams) } diff --git a/ginS/gins.go b/ginS/gins.go index 3e6a92eb..40088172 100644 --- a/ginS/gins.go +++ b/ginS/gins.go @@ -12,8 +12,10 @@ import ( "github.com/gin-gonic/gin" ) -var once sync.Once -var internalEngine *gin.Engine +var ( + once sync.Once + internalEngine *gin.Engine +) func engine() *gin.Engine { once.Do(func() { diff --git a/gin_integration_test.go b/gin_integration_test.go index 3082bc2c..c032d837 100644 --- a/gin_integration_test.go +++ b/gin_integration_test.go @@ -28,7 +28,6 @@ import ( // params[1]=response status (custom compare status) default:"200 OK" // params[2]=response body (custom compare content) default:"it worked" func testRequest(t *testing.T, params ...string) { - if len(params) == 0 { t.Fatal("url cannot be empty") } @@ -47,12 +46,12 @@ func testRequest(t *testing.T, params ...string) { body, ioerr := io.ReadAll(resp.Body) require.NoError(t, ioerr) - var responseStatus = "200 OK" + responseStatus := "200 OK" if len(params) > 1 && params[1] != "" { responseStatus = params[1] } - var responseBody = "it worked" + responseBody := "it worked" if len(params) > 2 && params[2] != "" { responseBody = params[2] } @@ -170,7 +169,7 @@ func TestRunTLS(t *testing.T) { } func TestPusher(t *testing.T) { - var html = template.Must(template.New("https").Parse(` + html := template.Must(template.New("https").Parse(` Https Test diff --git a/gin_test.go b/gin_test.go index 250269e5..be076537 100644 --- a/gin_test.go +++ b/gin_test.go @@ -46,7 +46,7 @@ func setupHTMLFiles(t *testing.T, mode string, tls bool, loadMethod func(*Engine }) router.GET("/raw", func(c *Context) { c.HTML(http.StatusOK, "raw.tmpl", map[string]any{ - "now": time.Date(2017, 07, 01, 0, 0, 0, 0, time.UTC), + "now": time.Date(2017, 07, 01, 0, 0, 0, 0, time.UTC), //nolint:gofumpt }) }) }) @@ -883,7 +883,7 @@ func TestWithOptionFunc(t *testing.T) { type Birthday string func (b *Birthday) UnmarshalParam(param string) error { - *b = Birthday(strings.Replace(param, "-", "/", -1)) + *b = Birthday(strings.ReplaceAll(param, "-", "/")) return nil } diff --git a/githubapi_test.go b/githubapi_test.go index 0c86af2e..20d4aeaf 100644 --- a/githubapi_test.go +++ b/githubapi_test.go @@ -298,8 +298,8 @@ func TestShouldBindUri(t *testing.T) { router.Handle(http.MethodGet, "/rest/:name/:id", func(c *Context) { var person Person require.NoError(t, c.ShouldBindUri(&person)) - assert.NotEqual(t, "", person.Name) - assert.NotEqual(t, "", person.ID) + assert.NotEmpty(t, person.Name) + assert.NotEmpty(t, person.ID) c.String(http.StatusOK, "ShouldBindUri test OK") }) @@ -320,8 +320,8 @@ func TestBindUri(t *testing.T) { router.Handle(http.MethodGet, "/rest/:name/:id", func(c *Context) { var person Person require.NoError(t, c.BindUri(&person)) - assert.NotEqual(t, "", person.Name) - assert.NotEqual(t, "", person.ID) + assert.NotEmpty(t, person.Name) + assert.NotEmpty(t, person.ID) c.String(http.StatusOK, "BindUri test OK") }) diff --git a/go.mod b/go.mod index 0a5c626d..8c1f92d3 100644 --- a/go.mod +++ b/go.mod @@ -38,9 +38,10 @@ require ( go.uber.org/mock v0.5.0 // indirect golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect golang.org/x/crypto v0.38.0 // indirect - golang.org/x/mod v0.18.0 // indirect + golang.org/x/lint v0.0.0-20241112194109-818c5a804067 // indirect + golang.org/x/mod v0.24.0 // indirect golang.org/x/sync v0.14.0 // indirect golang.org/x/sys v0.33.0 // indirect golang.org/x/text v0.25.0 // indirect - golang.org/x/tools v0.22.0 // indirect + golang.org/x/tools v0.33.0 // indirect ) diff --git a/go.sum b/go.sum index b047363b..a489a214 100644 --- a/go.sum +++ b/go.sum @@ -82,22 +82,38 @@ go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= +golang.org/x/lint v0.0.0-20241112194109-818c5a804067 h1:adDmSQyFTCiv19j015EGKJBoaa7ElV0Q1Wovb/4G7NA= +golang.org/x/lint v0.0.0-20241112194109-818c5a804067/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= +golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc= +golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= diff --git a/internal/bytesconv/bytesconv_test.go b/internal/bytesconv/bytesconv_test.go index eeaad5ee..497069ce 100644 --- a/internal/bytesconv/bytesconv_test.go +++ b/internal/bytesconv/bytesconv_test.go @@ -12,8 +12,10 @@ import ( "time" ) -var testString = "Albert Einstein: Logic will get you from A to B. Imagination will take you everywhere." -var testBytes = []byte(testString) +var ( + testString = "Albert Einstein: Logic will get you from A to B. Imagination will take you everywhere." + testBytes = []byte(testString) +) func rawBytesToStr(b []byte) string { return string(b) diff --git a/internal/fs/fs.go b/internal/fs/fs.go index 524ac08b..c2530383 100644 --- a/internal/fs/fs.go +++ b/internal/fs/fs.go @@ -13,7 +13,6 @@ type FileSystem struct { // Open passes `Open` to the upstream implementation and return an [fs.File]. func (o FileSystem) Open(name string) (fs.File, error) { f, err := o.FileSystem.Open(name) - if err != nil { return nil, err } diff --git a/logger_test.go b/logger_test.go index de00c499..30b25290 100644 --- a/logger_test.go +++ b/logger_test.go @@ -371,11 +371,11 @@ func TestErrorLogger(t *testing.T) { w := PerformRequest(router, http.MethodGet, "/error") assert.Equal(t, http.StatusOK, w.Code) - assert.Equal(t, "{\"error\":\"this is an error\"}", w.Body.String()) + assert.JSONEq(t, "{\"error\":\"this is an error\"}", w.Body.String()) w = PerformRequest(router, http.MethodGet, "/abort") assert.Equal(t, http.StatusUnauthorized, w.Code) - assert.Equal(t, "{\"error\":\"no authorized\"}", w.Body.String()) + assert.JSONEq(t, "{\"error\":\"no authorized\"}", w.Body.String()) w = PerformRequest(router, http.MethodGet, "/print") assert.Equal(t, http.StatusInternalServerError, w.Code) diff --git a/middleware_test.go b/middleware_test.go index 4390def7..8dc7c3b3 100644 --- a/middleware_test.go +++ b/middleware_test.go @@ -249,5 +249,5 @@ func TestMiddlewareWrite(t *testing.T) { w := PerformRequest(router, http.MethodGet, "/") assert.Equal(t, http.StatusBadRequest, w.Code) - assert.Equal(t, strings.Replace("hola\nbar{\"foo\":\"bar\"}{\"foo\":\"bar\"}event:test\ndata:message\n\n", " ", "", -1), strings.Replace(w.Body.String(), " ", "", -1)) + assert.Equal(t, strings.ReplaceAll("hola\nbar{\"foo\":\"bar\"}{\"foo\":\"bar\"}event:test\ndata:message\n\n", " ", ""), strings.ReplaceAll(w.Body.String(), " ", "")) } diff --git a/mode.go b/mode.go index 13aa3be0..cc313437 100644 --- a/mode.go +++ b/mode.go @@ -44,8 +44,10 @@ var DefaultWriter io.Writer = os.Stdout // DefaultErrorWriter is the default io.Writer used by Gin to debug errors var DefaultErrorWriter io.Writer = os.Stderr -var ginMode int32 = debugCode -var modeName atomic.Value +var ( + ginMode int32 = debugCode + modeName atomic.Value +) func init() { mode := os.Getenv(EnvGinMode) diff --git a/render/html.go b/render/html.go index f5e7455a..965d84c6 100644 --- a/render/html.go +++ b/render/html.go @@ -67,6 +67,7 @@ func (r HTMLDebug) Instance(name string, data any) Render { Data: data, } } + func (r HTMLDebug) loadTemplate() *template.Template { if r.FuncMap == nil { r.FuncMap = template.FuncMap{} diff --git a/render/render_test.go b/render/render_test.go index 4dd2a3af..447ea6a8 100644 --- a/render/render_test.go +++ b/render/render_test.go @@ -38,7 +38,7 @@ func TestRenderJSON(t *testing.T) { err := (JSON{data}).Render(w) require.NoError(t, err) - assert.Equal(t, "{\"foo\":\"bar\",\"html\":\"\\u003cb\\u003e\"}", w.Body.String()) + assert.JSONEq(t, "{\"foo\":\"bar\",\"html\":\"\\u003cb\\u003e\"}", w.Body.String()) assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type")) } @@ -60,7 +60,7 @@ func TestRenderIndentedJSON(t *testing.T) { err := (IndentedJSON{data}).Render(w) require.NoError(t, err) - assert.Equal(t, "{\n \"bar\": \"foo\",\n \"foo\": \"bar\"\n}", w.Body.String()) + assert.JSONEq(t, "{\n \"bar\": \"foo\",\n \"foo\": \"bar\"\n}", w.Body.String()) assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type")) } @@ -85,7 +85,7 @@ func TestRenderSecureJSON(t *testing.T) { err1 := (SecureJSON{"while(1);", data}).Render(w1) require.NoError(t, err1) - assert.Equal(t, "{\"foo\":\"bar\"}", w1.Body.String()) + assert.JSONEq(t, "{\"foo\":\"bar\"}", w1.Body.String()) assert.Equal(t, "application/json; charset=utf-8", w1.Header().Get("Content-Type")) w2 := httptest.NewRecorder() @@ -194,7 +194,7 @@ func TestRenderJsonpJSONError2(t *testing.T) { e := (JsonpJSON{"", data}).Render(w) require.NoError(t, e) - assert.Equal(t, "{\"foo\":\"bar\"}", w.Body.String()) + assert.JSONEq(t, "{\"foo\":\"bar\"}", w.Body.String()) assert.Equal(t, "application/javascript; charset=utf-8", w.Header().Get("Content-Type")) } @@ -217,7 +217,7 @@ func TestRenderAsciiJSON(t *testing.T) { err := (AsciiJSON{data1}).Render(w1) require.NoError(t, err) - assert.Equal(t, "{\"lang\":\"GO\\u8bed\\u8a00\",\"tag\":\"\\u003cbr\\u003e\"}", w1.Body.String()) + assert.JSONEq(t, "{\"lang\":\"GO\\u8bed\\u8a00\",\"tag\":\"\\u003cbr\\u003e\"}", w1.Body.String()) assert.Equal(t, "application/json", w1.Header().Get("Content-Type")) w2 := httptest.NewRecorder() @@ -244,7 +244,7 @@ func TestRenderPureJSON(t *testing.T) { } err := (PureJSON{data}).Render(w) require.NoError(t, err) - assert.Equal(t, "{\"foo\":\"bar\",\"html\":\"\"}\n", w.Body.String()) + assert.JSONEq(t, "{\"foo\":\"bar\",\"html\":\"\"}\n", w.Body.String()) assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type")) } diff --git a/routes_test.go b/routes_test.go index 995ff51c..1cae3fce 100644 --- a/routes_test.go +++ b/routes_test.go @@ -484,7 +484,7 @@ func TestRouterMiddlewareAndStatic(t *testing.T) { assert.Contains(t, w.Body.String(), "package gin") // Content-Type='text/plain; charset=utf-8' when go version <= 1.16, // else, Content-Type='text/x-go; charset=utf-8' - assert.NotEqual(t, "", w.Header().Get("Content-Type")) + assert.NotEmpty(t, w.Header().Get("Content-Type")) assert.NotEqual(t, "Mon, 02 Jan 2006 15:04:05 MST", w.Header().Get("Last-Modified")) assert.Equal(t, "Mon, 02 Jan 2006 15:04:05 MST", w.Header().Get("Expires")) assert.Equal(t, "Gin Framework", w.Header().Get("x-GIN")) @@ -764,7 +764,7 @@ func TestRouteContextHoldsFullPath(t *testing.T) { // Test not found router.Use(func(c *Context) { // For not found routes full path is empty - assert.Equal(t, "", c.FullPath()) + assert.Empty(t, c.FullPath()) }) w := PerformRequest(router, http.MethodGet, "/not-found") diff --git a/tree_test.go b/tree_test.go index 74eb6104..b580007d 100644 --- a/tree_test.go +++ b/tree_test.go @@ -481,7 +481,7 @@ func TestTreeDuplicatePath(t *testing.T) { } } - //printChildren(tree, "") + // printChildren(tree, "") checkRequests(t, tree, testRequests{ {"/", false, "/", nil}, @@ -532,7 +532,7 @@ func TestTreeCatchAllConflictRoot(t *testing.T) { func TestTreeCatchMaxParams(t *testing.T) { tree := &node{} - var route = "/cmd/*filepath" + route := "/cmd/*filepath" tree.addRoute(route, fakeHandler(route)) } @@ -692,7 +692,7 @@ func TestTreeRootTrailingSlashRedirect(t *testing.T) { } func TestRedirectTrailingSlash(t *testing.T) { - var data = []struct { + data := []struct { path string }{ {"/hello/:name"}, diff --git a/utils_test.go b/utils_test.go index 8098c681..dc9886d7 100644 --- a/utils_test.go +++ b/utils_test.go @@ -94,7 +94,7 @@ func somefunction() { } func TestJoinPaths(t *testing.T) { - assert.Equal(t, "", joinPaths("", "")) + assert.Empty(t, joinPaths("", "")) assert.Equal(t, "/", joinPaths("", "/")) assert.Equal(t, "/a", joinPaths("/a", "")) assert.Equal(t, "/a/", joinPaths("/a/", ""))