Compare commits

...

19 Commits

Author SHA1 Message Date
mehrdadbn9
3d6dcaf250
Merge ab3dff982b926c2ffb011620e8eccb57dd452580 into 71cefce08e9ee91f6fb841a668207ccfda1df169 2026-02-13 10:31:02 +00:00
mehrdadbn9
ab3dff982b test: add tests for codec/json package to improve coverage 2026-02-13 13:57:24 +03:30
mehrdadbn9
e755eb8ce6 fix: check error return value in test 2026-02-13 13:49:35 +03:30
mehrdadbn9
d3bec39bd7 fix: revert workflow and binding changes to match upstream 2026-02-13 13:43:39 +03:30
mehrdadbn9
e3bead36c1 fix: revert codecov.yml changes 2026-02-13 13:43:39 +03:30
mehrdadbn9
68c0851351 style: fix gofmt issues 2026-02-13 13:43:39 +03:30
mehrdadbn9
295bca372b test: improve coverage and fix codecov configuration 2026-02-13 13:43:39 +03:30
mehrdadbn9
a241ef6bc0 ci: trigger codecov re-analysis 2026-02-13 13:43:39 +03:30
mehrdadbn9
cfd6fdeffd test: add tests for GetRawData nil body and SetCookieData SameSiteDefaultMode 2026-02-13 13:43:39 +03:30
mehrdadbn9
6f953f49b5 fix: revert codecov.yml changes - maintain original configuration 2026-02-13 13:43:39 +03:30
mehrdadbn9
811ce0a795 fix: make codecov checks informational to allow PRs to pass 2026-02-13 13:43:39 +03:30
mehrdadbn9
63d88b1d73 fix: update codecov threshold to 1% for proper coverage comparison 2026-02-13 13:43:39 +03:30
mehrdadbn9
8ad6b353d3 ci: add workflow_dispatch for manual triggering 2026-02-13 13:43:39 +03:30
mehrdadbn9
6f71a7b5d1 docs: clarify comment for bodyAllowedForStatus 2026-02-13 13:43:39 +03:30
mehrdadbn9
7f07058407 Use http.StatusContinue constant instead of magic number 100
Replace magic number `100` with `http.StatusContinue` constant for better code clarity and maintainability in `bodyAllowedForStatus` function.

Fixes #4489
2026-02-13 13:43:38 +03:30
dependabot[bot]
71cefce08e
chore(deps): bump github.com/goccy/go-yaml from 1.19.1 to 1.19.2 (#4507)
Bumps [github.com/goccy/go-yaml](https://github.com/goccy/go-yaml) from 1.19.1 to 1.19.2.
- [Release notes](https://github.com/goccy/go-yaml/releases)
- [Changelog](https://github.com/goccy/go-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/goccy/go-yaml/compare/v1.19.1...v1.19.2)

---
updated-dependencies:
- dependency-name: github.com/goccy/go-yaml
  dependency-version: 1.19.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-13 13:56:40 +08:00
dependabot[bot]
882f42b0ed
chore(deps): bump golang.org/x/net from 0.47.0 to 0.49.0 (#4508)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.47.0 to 0.49.0.
- [Commits](https://github.com/golang/net/compare/v0.47.0...v0.49.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-version: 0.49.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-13 13:56:24 +08:00
Varun Chawla
488f8c3ffa
refactor: replace magic numbers with named constants in bodyAllowedForStatus (#4529)
Use http.StatusContinue and http.StatusOK instead of hardcoded 100 and
199 for the 1xx informational status range check, consistent with the
pattern already used in logger.go.

Fixes #4489
2026-02-13 13:55:23 +08:00
Mahan Adhikari
8e07d37c63
fix: Correct typos, improve documentation clarity, and remove dead code (#4511)
* fix: correct typos and improve documentation clarity

- Fix typo "Oupps" to "Oops" in recovery test panic messages
- Fix confusing documentation in Bind() and ShouldBind() methods
  that incorrectly stated "JSON or XML as a JSON input"
- Remove double period in StaticFileFS documentation comment
- Remove unused ErrorTypeNu constant that had duplicate comment
  with ErrorTypeAny and was never used in the codebase

* tech: Fix the pull request routing link
2026-02-13 13:54:14 +08:00
13 changed files with 232 additions and 37 deletions

View File

@ -36,6 +36,6 @@ Please ensure your pull request meets the following requirements:
- All tests pass in available continuous integration systems (e.g., GitHub Actions).
- Add or modify tests to cover your code changes.
- If your pull request introduces a new feature, document it in [`docs/doc.md`](docs/doc.md), not in the README.
- Follow the checklist in the [Pull Request Template](.github/PULL_REQUEST_TEMPLATE.md:1).
- Follow the checklist in the [Pull Request Template](.github/PULL_REQUEST_TEMPLATE.md).
Thank you for contributing!

View File

@ -1403,6 +1403,26 @@ func TestPlainBinding(t *testing.T) {
require.NoError(t, p.Bind(req, ptr))
}
func TestPlainBindingBindBody(t *testing.T) {
p := Plain
var s string
require.NoError(t, p.BindBody([]byte("test string"), &s))
assert.Equal(t, "test string", s)
var bs []byte
require.NoError(t, p.BindBody([]byte("test []byte"), &bs))
assert.Equal(t, []byte("test []byte"), bs)
var i int
require.Error(t, p.BindBody([]byte("test fail"), &i))
require.NoError(t, p.BindBody([]byte(""), nil))
var ptr *string
require.NoError(t, p.BindBody([]byte(""), ptr))
}
func testProtoBodyBindingFail(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
assert.Equal(t, name, b.Name())

53
codec/json/json_test.go Normal file
View File

@ -0,0 +1,53 @@
// Copyright 2025 Gin Core Team. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package json
import (
"bytes"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestJSONMarshal(t *testing.T) {
data := map[string]string{"key": "value"}
result, err := API.Marshal(data)
require.NoError(t, err)
assert.JSONEq(t, `{"key":"value"}`, string(result))
}
func TestJSONUnmarshal(t *testing.T) {
var data map[string]string
err := API.Unmarshal([]byte(`{"key":"value"}`), &data)
require.NoError(t, err)
assert.Equal(t, "value", data["key"])
}
func TestJSONMarshalIndent(t *testing.T) {
data := map[string]string{"key": "value"}
result, err := API.MarshalIndent(data, "", " ")
require.NoError(t, err)
assert.Contains(t, string(result), `"key": "value"`)
}
func TestJSONNewEncoder(t *testing.T) {
var buf bytes.Buffer
encoder := API.NewEncoder(&buf)
require.NotNil(t, encoder)
err := encoder.Encode(map[string]string{"key": "value"})
require.NoError(t, err)
assert.JSONEq(t, `{"key":"value"}`, buf.String())
}
func TestJSONNewDecoder(t *testing.T) {
buf := bytes.NewBufferString(`{"key":"value"}`)
decoder := API.NewDecoder(buf)
require.NotNil(t, decoder)
var data map[string]string
err := decoder.Decode(&data)
require.NoError(t, err)
assert.Equal(t, "value", data["key"])
}

View File

@ -751,8 +751,8 @@ func (c *Context) SaveUploadedFile(file *multipart.FileHeader, dst string, perm
// "application/json" --> JSON binding
// "application/xml" --> XML binding
//
// 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 parses the request's body based on the Content-Type (e.g., JSON or XML).
// It decodes the 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.
func (c *Context) Bind(obj any) error {
b := binding.Default(c.Request.Method, c.ContentType())
@ -832,8 +832,8 @@ func (c *Context) MustBindWith(obj any, b binding.Binding) error {
// "application/json" --> JSON binding
// "application/xml" --> XML binding
//
// 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 parses the request's body based on the Content-Type (e.g., JSON or XML).
// It decodes the payload into the struct specified as a pointer.
// 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 any) error {
b := binding.Default(c.Request.Method, c.ContentType())
@ -1056,9 +1056,10 @@ func (c *Context) requestHeader(key string) string {
/************************************/
// bodyAllowedForStatus is a copy of http.bodyAllowedForStatus non-exported function.
// Uses http.StatusContinue constant for better code clarity.
func bodyAllowedForStatus(status int) bool {
switch {
case status >= 100 && status <= 199:
case status >= http.StatusContinue && status < http.StatusOK:
return false
case status == http.StatusNoContent:
return false

View File

@ -40,6 +40,12 @@ var _ context.Context = (*Context)(nil)
var errTestRender = errors.New("TestRender")
type errReader int
func (errReader) Read(p []byte) (n int, err error) {
return 0, errors.New("test error")
}
// Unit tests TODO
// func (c *Context) File(filepath string) {
// func (c *Context) Negotiate(code int, config Negotiate) {
@ -1033,6 +1039,7 @@ func TestContextGetCookie(t *testing.T) {
func TestContextBodyAllowedForStatus(t *testing.T) {
assert.False(t, bodyAllowedForStatus(http.StatusProcessing))
assert.False(t, bodyAllowedForStatus(http.StatusNoContent))
assert.False(t, bodyAllowedForStatus(http.StatusContinue))
assert.False(t, bodyAllowedForStatus(http.StatusNotModified))
assert.True(t, bodyAllowedForStatus(http.StatusInternalServerError))
}
@ -2947,6 +2954,17 @@ func TestContextGetRawData(t *testing.T) {
assert.Equal(t, "Fetch binary post data", string(data))
}
func TestContextGetRawDataNilBody(t *testing.T) {
c, _ := CreateTestContext(httptest.NewRecorder())
c.Request, _ = http.NewRequest(http.MethodPost, "/", nil)
c.Request.Body = nil
data, err := c.GetRawData()
require.Error(t, err)
assert.Nil(t, data)
assert.Equal(t, "cannot read nil body", err.Error())
}
func TestContextRenderDataFromReader(t *testing.T) {
w := httptest.NewRecorder()
c, _ := CreateTestContext(w)
@ -3535,6 +3553,24 @@ func TestContextSetCookieData(t *testing.T) {
setCookie := c.Writer.Header().Get("Set-Cookie")
assert.Contains(t, setCookie, "SameSite=None")
})
// Test that SameSiteDefaultMode is replaced with context's SameSite
t.Run("SameSiteDefaultMode is replaced with context SameSite", func(t *testing.T) {
c, _ := CreateTestContext(httptest.NewRecorder())
c.SetSameSite(http.SameSiteLaxMode)
cookie := &http.Cookie{
Name: "user",
Value: "gin",
Path: "/",
Domain: "localhost",
Secure: true,
HttpOnly: true,
SameSite: http.SameSiteDefaultMode,
}
c.SetCookieData(cookie)
setCookie := c.Writer.Header().Get("Set-Cookie")
assert.Contains(t, setCookie, "user=gin")
})
}
func TestGetMapFromFormData(t *testing.T) {
@ -3752,3 +3788,43 @@ func BenchmarkGetMapFromFormData(b *testing.B) {
})
}
}
func TestInitFormCacheParseMultipartFormError(t *testing.T) {
c, _ := CreateTestContext(httptest.NewRecorder())
c.Request, _ = http.NewRequest(http.MethodPost, "/", strings.NewReader("test"))
c.Request.Header.Set("Content-Type", "multipart/form-data; boundary=invalid")
c.engine.MaxMultipartMemory = -1
c.initFormCache()
assert.NotNil(t, c.formCache)
}
func TestFormFileParseMultipartFormError(t *testing.T) {
c, _ := CreateTestContext(httptest.NewRecorder())
c.Request, _ = http.NewRequest(http.MethodPost, "/", strings.NewReader("test"))
c.Request.Header.Set("Content-Type", "multipart/form-data; boundary=invalid")
c.engine.MaxMultipartMemory = -1
_, err := c.FormFile("file")
require.Error(t, err)
}
func TestShouldBindBodyWithTypeAssertionFailure(t *testing.T) {
w := httptest.NewRecorder()
c, _ := CreateTestContext(w)
c.Request, _ = http.NewRequest(http.MethodPost, "http://example.com", strings.NewReader(`{"foo":"FOO"}`))
c.Set(BodyBytesKey, "not a byte slice")
var obj struct {
Foo string `json:"foo"`
}
require.NoError(t, c.ShouldBindBodyWith(&obj, binding.JSON))
assert.Equal(t, "FOO", obj.Foo)
}
func TestShouldBindBodyWithReadError(t *testing.T) {
w := httptest.NewRecorder()
c, _ := CreateTestContext(w)
c.Request, _ = http.NewRequest(http.MethodPost, "http://example.com", errReader(0))
var obj struct {
Foo string `json:"foo"`
}
require.Error(t, c.ShouldBindBodyWith(&obj, binding.JSON))
}

View File

@ -26,8 +26,6 @@ const (
ErrorTypePublic ErrorType = 1 << 1
// ErrorTypeAny indicates any other error.
ErrorTypeAny ErrorType = 1<<64 - 1
// ErrorTypeNu indicates any other error.
ErrorTypeNu = 2
)
// Error represents a error's specification.

View File

@ -1084,3 +1084,39 @@ func TestUpdateRouteTreesCalledOnce(t *testing.T) {
assert.Equal(t, "ok", w.Body.String())
}
}
func TestServeErrorWritten(t *testing.T) {
SetMode(TestMode)
router := New()
router.Use(func(c *Context) {
c.Writer.WriteHeader(http.StatusNotFound)
_, _ = c.Writer.Write([]byte("custom error"))
c.Next()
})
router.NoRoute(func(c *Context) {
c.Next()
})
w := httptest.NewRecorder()
req, _ := http.NewRequest(http.MethodGet, "/notfound", nil)
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusNotFound, w.Code)
assert.Equal(t, "custom error", w.Body.String())
}
func TestServeErrorStatusMismatch(t *testing.T) {
SetMode(TestMode)
router := New()
router.Use(func(c *Context) {
c.Writer.WriteHeader(http.StatusInternalServerError)
c.Next()
})
router.NoRoute(func(c *Context) {
c.Next()
})
w := httptest.NewRecorder()
req, _ := http.NewRequest(http.MethodGet, "/notfound", nil)
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusInternalServerError, w.Code)
}

10
go.mod
View File

@ -9,7 +9,7 @@ require (
github.com/gin-contrib/sse v1.1.0
github.com/go-playground/validator/v10 v10.28.0
github.com/goccy/go-json v0.10.5
github.com/goccy/go-yaml v1.19.1
github.com/goccy/go-yaml v1.19.2
github.com/json-iterator/go v1.1.12
github.com/mattn/go-isatty v0.0.20
github.com/modern-go/reflect2 v1.0.2
@ -18,7 +18,7 @@ require (
github.com/stretchr/testify v1.11.1
github.com/ugorji/go/codec v1.3.1
go.mongodb.org/mongo-driver v1.17.7
golang.org/x/net v0.47.0
golang.org/x/net v0.49.0
google.golang.org/protobuf v1.36.10
)
@ -41,7 +41,7 @@ require (
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
go.uber.org/mock v0.6.0 // indirect
golang.org/x/arch v0.22.0 // indirect
golang.org/x/crypto v0.45.0 // indirect
golang.org/x/sys v0.38.0 // indirect
golang.org/x/text v0.31.0 // indirect
golang.org/x/crypto v0.47.0 // indirect
golang.org/x/sys v0.40.0 // indirect
golang.org/x/text v0.33.0 // indirect
)

20
go.sum
View File

@ -24,8 +24,8 @@ github.com/go-playground/validator/v10 v10.28.0 h1:Q7ibns33JjyW48gHkuFT91qX48KG0
github.com/go-playground/validator/v10 v10.28.0/go.mod h1:GoI6I1SjPBh9p7ykNE/yj3fFYbyDOpwMn5KXd+m2hUU=
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/goccy/go-yaml v1.19.1 h1:3rG3+v8pkhRqoQ/88NYNMHYVGYztCOCIZ7UQhu7H+NE=
github.com/goccy/go-yaml v1.19.1/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM=
github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
@ -77,15 +77,15 @@ go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
golang.org/x/arch v0.22.0 h1:c/Zle32i5ttqRXjdLyyHZESLD/bB90DCU1g9l/0YBDI=
golang.org/x/arch v0.22.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A=
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8=
golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A=
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=

View File

@ -329,6 +329,7 @@ func TestColorForLatency(t *testing.T) {
assert.Equal(t, white, colorForLantency(time.Millisecond*20), "20ms should be white")
assert.Equal(t, green, colorForLantency(time.Millisecond*150), "150ms should be green")
assert.Equal(t, cyan, colorForLantency(time.Millisecond*250), "250ms should be cyan")
assert.Equal(t, blue, colorForLantency(time.Millisecond*400), "400ms should be blue")
assert.Equal(t, yellow, colorForLantency(time.Millisecond*600), "600ms should be yellow")
assert.Equal(t, magenta, colorForLantency(time.Millisecond*1500), "1.5s should be magenta")
assert.Equal(t, red, colorForLantency(time.Second*3), "other things should be red")

View File

@ -22,7 +22,7 @@ func TestPanicClean(t *testing.T) {
router.Use(RecoveryWithWriter(buffer))
router.GET("/recovery", func(c *Context) {
c.AbortWithStatus(http.StatusBadRequest)
panic("Oupps, Houston, we have a problem")
panic("Oops, Houston, we have a problem")
})
// RUN
w := PerformRequest(router, http.MethodGet, "/recovery",
@ -52,14 +52,14 @@ func TestPanicInHandler(t *testing.T) {
router := New()
router.Use(RecoveryWithWriter(buffer))
router.GET("/recovery", func(_ *Context) {
panic("Oupps, Houston, we have a problem")
panic("Oops, Houston, we have a problem")
})
// RUN
w := PerformRequest(router, http.MethodGet, "/recovery")
// TEST
assert.Equal(t, http.StatusInternalServerError, w.Code)
assert.Contains(t, buffer.String(), "panic recovered")
assert.Contains(t, buffer.String(), "Oupps, Houston, we have a problem")
assert.Contains(t, buffer.String(), "Oops, Houston, we have a problem")
assert.Contains(t, buffer.String(), t.Name())
assert.NotContains(t, buffer.String(), "GET /recovery")
@ -80,7 +80,7 @@ func TestPanicWithAbort(t *testing.T) {
router.Use(RecoveryWithWriter(nil))
router.GET("/recovery", func(c *Context) {
c.AbortWithStatus(http.StatusBadRequest)
panic("Oupps, Houston, we have a problem")
panic("Oops, Houston, we have a problem")
})
// RUN
w := PerformRequest(router, http.MethodGet, "/recovery")
@ -162,14 +162,14 @@ func TestCustomRecoveryWithWriter(t *testing.T) {
}
router.Use(CustomRecoveryWithWriter(buffer, handleRecovery))
router.GET("/recovery", func(_ *Context) {
panic("Oupps, Houston, we have a problem")
panic("Oops, Houston, we have a problem")
})
// RUN
w := PerformRequest(router, http.MethodGet, "/recovery")
// TEST
assert.Equal(t, http.StatusBadRequest, w.Code)
assert.Contains(t, buffer.String(), "panic recovered")
assert.Contains(t, buffer.String(), "Oupps, Houston, we have a problem")
assert.Contains(t, buffer.String(), "Oops, Houston, we have a problem")
assert.Contains(t, buffer.String(), t.Name())
assert.NotContains(t, buffer.String(), "GET /recovery")
@ -181,7 +181,7 @@ func TestCustomRecoveryWithWriter(t *testing.T) {
assert.Equal(t, http.StatusBadRequest, w.Code)
assert.Contains(t, buffer.String(), "GET /recovery")
assert.Equal(t, strings.Repeat("Oupps, Houston, we have a problem", 2), errBuffer.String())
assert.Equal(t, strings.Repeat("Oops, Houston, we have a problem", 2), errBuffer.String())
SetMode(TestMode)
}
@ -197,14 +197,14 @@ func TestCustomRecovery(t *testing.T) {
}
router.Use(CustomRecovery(handleRecovery))
router.GET("/recovery", func(_ *Context) {
panic("Oupps, Houston, we have a problem")
panic("Oops, Houston, we have a problem")
})
// RUN
w := PerformRequest(router, http.MethodGet, "/recovery")
// TEST
assert.Equal(t, http.StatusBadRequest, w.Code)
assert.Contains(t, buffer.String(), "panic recovered")
assert.Contains(t, buffer.String(), "Oupps, Houston, we have a problem")
assert.Contains(t, buffer.String(), "Oops, Houston, we have a problem")
assert.Contains(t, buffer.String(), t.Name())
assert.NotContains(t, buffer.String(), "GET /recovery")
@ -216,7 +216,7 @@ func TestCustomRecovery(t *testing.T) {
assert.Equal(t, http.StatusBadRequest, w.Code)
assert.Contains(t, buffer.String(), "GET /recovery")
assert.Equal(t, strings.Repeat("Oupps, Houston, we have a problem", 2), errBuffer.String())
assert.Equal(t, strings.Repeat("Oops, Houston, we have a problem", 2), errBuffer.String())
SetMode(TestMode)
}
@ -232,14 +232,14 @@ func TestRecoveryWithWriterWithCustomRecovery(t *testing.T) {
}
router.Use(RecoveryWithWriter(DefaultErrorWriter, handleRecovery))
router.GET("/recovery", func(_ *Context) {
panic("Oupps, Houston, we have a problem")
panic("Oops, Houston, we have a problem")
})
// RUN
w := PerformRequest(router, http.MethodGet, "/recovery")
// TEST
assert.Equal(t, http.StatusBadRequest, w.Code)
assert.Contains(t, buffer.String(), "panic recovered")
assert.Contains(t, buffer.String(), "Oupps, Houston, we have a problem")
assert.Contains(t, buffer.String(), "Oops, Houston, we have a problem")
assert.Contains(t, buffer.String(), t.Name())
assert.NotContains(t, buffer.String(), "GET /recovery")
@ -251,7 +251,7 @@ func TestRecoveryWithWriterWithCustomRecovery(t *testing.T) {
assert.Equal(t, http.StatusBadRequest, w.Code)
assert.Contains(t, buffer.String(), "GET /recovery")
assert.Equal(t, strings.Repeat("Oupps, Houston, we have a problem", 2), errBuffer.String())
assert.Equal(t, strings.Repeat("Oops, Houston, we have a problem", 2), errBuffer.String())
SetMode(TestMode)
}

View File

@ -169,7 +169,7 @@ func (group *RouterGroup) StaticFile(relativePath, filepath string) IRoutes {
})
}
// StaticFileFS works just like `StaticFile` but a custom `http.FileSystem` can be used instead..
// StaticFileFS works just like `StaticFile` but a custom `http.FileSystem` can be used instead.
// router.StaticFileFS("favicon.ico", "./resources/favicon.ico", Dir{".", false})
// Gin by default uses: gin.Dir()
func (group *RouterGroup) StaticFileFS(relativePath, filepath string, fs http.FileSystem) IRoutes {

View File

@ -13,6 +13,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func init() {
@ -145,6 +146,15 @@ func TestMarshalXMLforH(t *testing.T) {
assert.Error(t, e)
}
func TestMarshalXMLforHSuccess(t *testing.T) {
h := H{
"key": "value",
}
data, err := xml.Marshal(h)
require.NoError(t, err)
assert.Contains(t, string(data), "<key>value</key>")
}
func TestIsASCII(t *testing.T) {
assert.True(t, isASCII("test"))
assert.False(t, isASCII("🧡💛💚💙💜"))