Compare commits

...

10 Commits

Author SHA1 Message Date
Muyao CHEN
116d0b112e Araneae: integrate custom context interfaces into Gin
Some checks are pending
CodeQL / Analyze (go) (push) Waiting to run
Run Tests / lint (push) Waiting to run
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.21, ~/.cache/go-build, ubuntu-latest, ) (push) Blocked by required conditions
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.21, ~/.cache/go-build, ubuntu-latest, -race) (push) Blocked by required conditions
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.21, ~/.cache/go-build, ubuntu-latest, -tags "sonic avx") (push) Blocked by required conditions
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.21, ~/.cache/go-build, ubuntu-latest, -tags go_json) (push) Blocked by required conditions
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.21, ~/.cache/go-build, ubuntu-latest, -tags nomsgpack) (push) Blocked by required conditions
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.21, ~/Library/Caches/go-build, macos-latest, ) (push) Blocked by required conditions
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.21, ~/Library/Caches/go-build, macos-latest, -race) (push) Blocked by required conditions
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.21, ~/Library/Caches/go-build, macos-latest, -tags "sonic avx") (push) Blocked by required conditions
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.21, ~/Library/Caches/go-build, macos-latest, -tags go_json) (push) Blocked by required conditions
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.21, ~/Library/Caches/go-build, macos-latest, -tags nomsgpack) (push) Blocked by required conditions
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.22, ~/.cache/go-build, ubuntu-latest, ) (push) Blocked by required conditions
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.22, ~/.cache/go-build, ubuntu-latest, -race) (push) Blocked by required conditions
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.22, ~/.cache/go-build, ubuntu-latest, -tags "sonic avx") (push) Blocked by required conditions
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.22, ~/.cache/go-build, ubuntu-latest, -tags go_json) (push) Blocked by required conditions
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.22, ~/.cache/go-build, ubuntu-latest, -tags nomsgpack) (push) Blocked by required conditions
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.22, ~/Library/Caches/go-build, macos-latest, ) (push) Blocked by required conditions
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.22, ~/Library/Caches/go-build, macos-latest, -race) (push) Blocked by required conditions
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.22, ~/Library/Caches/go-build, macos-latest, -tags "sonic avx") (push) Blocked by required conditions
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.22, ~/Library/Caches/go-build, macos-latest, -tags go_json) (push) Blocked by required conditions
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.22, ~/Library/Caches/go-build, macos-latest, -tags nomsgpack) (push) Blocked by required conditions
2024-09-28 10:22:47 +02:00
takanuva15
f05f966a08
feat(form): Support default values for collections in form binding (#4048)
Some checks failed
CodeQL / Analyze (go) (push) Has been cancelled
Run Tests / lint (push) Has been cancelled
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.21, ~/.cache/go-build, ubuntu-latest, ) (push) Has been cancelled
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.21, ~/.cache/go-build, ubuntu-latest, -race) (push) Has been cancelled
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.21, ~/.cache/go-build, ubuntu-latest, -tags "sonic avx") (push) Has been cancelled
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.21, ~/.cache/go-build, ubuntu-latest, -tags go_json) (push) Has been cancelled
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.21, ~/.cache/go-build, ubuntu-latest, -tags nomsgpack) (push) Has been cancelled
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.21, ~/Library/Caches/go-build, macos-latest, ) (push) Has been cancelled
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.21, ~/Library/Caches/go-build, macos-latest, -race) (push) Has been cancelled
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.21, ~/Library/Caches/go-build, macos-latest, -tags "sonic avx") (push) Has been cancelled
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.21, ~/Library/Caches/go-build, macos-latest, -tags go_json) (push) Has been cancelled
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.21, ~/Library/Caches/go-build, macos-latest, -tags nomsgpack) (push) Has been cancelled
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.22, ~/.cache/go-build, ubuntu-latest, ) (push) Has been cancelled
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.22, ~/.cache/go-build, ubuntu-latest, -race) (push) Has been cancelled
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.22, ~/.cache/go-build, ubuntu-latest, -tags "sonic avx") (push) Has been cancelled
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.22, ~/.cache/go-build, ubuntu-latest, -tags go_json) (push) Has been cancelled
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.22, ~/.cache/go-build, ubuntu-latest, -tags nomsgpack) (push) Has been cancelled
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.22, ~/Library/Caches/go-build, macos-latest, ) (push) Has been cancelled
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.22, ~/Library/Caches/go-build, macos-latest, -race) (push) Has been cancelled
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.22, ~/Library/Caches/go-build, macos-latest, -tags "sonic avx") (push) Has been cancelled
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.22, ~/Library/Caches/go-build, macos-latest, -tags go_json) (push) Has been cancelled
Run Tests / ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }} (1.22, ~/Library/Caches/go-build, macos-latest, -tags nomsgpack) (push) Has been cancelled
2024-09-21 23:24:18 +08:00
CC11001100
9d7c0e9e1a
feat(context): GetXxx added support for more go native types (#3633) 2024-09-15 08:58:59 +08:00
demouth
f2c861a24f
docs: fix route group example code (#4020) 2024-09-15 08:54:23 +08:00
Ahmad Saeed Goda
28e57f58b1
fix(form): Set default value for form fields (#4047)
- Use specified default value in struct tags when binding a request input to struct for validation, even if sent empty, not only when not sent at all.
- Add string field to `TestMappingDefault` test case.
- Add test case for not sent form field to default to the value specified via code.
- Add test case for form field sent empty to default to the value specified via code.

Fixes: How to apply default value if empty value provided by client during model binding? #4042, #13042df, #a41721a
2024-09-06 13:21:19 +08:00
Jo YoHan
3cb30679b5
feat(form): add array collection format in form binding (#3986)
* feat(form): add array collection format in form binding

* feat(form): add array collection format in form binding

* test(form): fix test code for array collection format in form binding
2024-08-24 14:16:30 +08:00
dependabot[bot]
cc4e11438c
chore(deps): bump golang.org/x/net from 0.25.0 to 0.27.0 (#4013)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.25.0 to 0.27.0.
- [Commits](https://github.com/golang/net/compare/v0.25.0...v0.27.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  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>
2024-07-14 20:34:34 +08:00
Matthieu MOREL
5f55c6a711
ci(lint): enable testifylint linter (#4010)
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2024-07-14 20:33:08 +08:00
Pierre-Henri Symoneaux
626d55b0c0
fix(gin): Do not panic when handling method not allowed on empty tree (#4003)
Signed-off-by: Pierre-Henri Symoneaux <pierre-henri.symoneaux@ovhcloud.com>
2024-06-22 22:19:04 +08:00
demouth
9c081de9cd
docs: fix typo in Gin Quick Start (#3997) 2024-06-16 00:28:08 +08:00
29 changed files with 1483 additions and 481 deletions

View File

@ -17,6 +17,7 @@ linters:
- nilerr
- nolintlint
- revive
- testifylint
- wastedassign
linters-settings:
@ -33,6 +34,8 @@ linters-settings:
- G112
- G201
- G203
testifylint:
enable-all: true
issues:
exclude-rules:

8
araneae_context.go Normal file
View File

@ -0,0 +1,8 @@
package gin
import "golang.org/x/net/context"
// BaseContext gets the basic context of the request
func (ctx *Context) BaseContext() context.Context {
return ctx.Request.Context()
}

310
araneae_request.go Normal file
View File

@ -0,0 +1,310 @@
package gin
import (
"mime/multipart"
"net/url"
"github.com/spf13/cast"
)
type IRequest interface {
// url query
// e.g. foo.com?a=1&b=bar&c[]=bar
QueryAll(key string) url.Values
QueryIntWithDefault(key string, defval int) (int, bool)
QueryInt64WithDefault(key string, defval int64) (int64, bool)
QueryFloat32WithDefault(key string, defval float32) (float32, bool)
QueryFloat64WithDefault(key string, defval float64) (float64, bool)
QueryBoolWithDefault(key string, defval bool) (bool, bool)
QueryStringWithDefault(key string, defval string) (string, bool)
QueryStringSliceWithDefault(key string, defval []string) ([]string, bool)
// url params
// e.g. /book/:id
Param(key string) string
ParamIntWithDefault(key string, defval int) (int, bool)
ParamInt64WithDefault(key string, defval int64) (int64, bool)
ParamFloat32WithDefault(key string, defval float32) (float32, bool)
ParamFloat64WithDefault(key string, defval float64) (float64, bool)
ParamBoolWithDefault(key string, defval bool) (bool, bool)
ParamStringWithDefault(key string, defval string) (string, bool)
// form
FormAllWithDefault(key string) url.Values
FormIntWithDefault(key string, defval int) (int, bool)
FormInt64WithDefault(key string, defval int64) (int64, bool)
FormFloat32WithDefault(key string, defval float32) (float32, bool)
FormFloat64WithDefault(key string, defval float64) (float64, bool)
FormBoolWithDefault(key string, defval bool) (bool, bool)
FormStringWithDefault(key string, defval string) (string, bool)
FormStringSliceWithDefault(key string, defval []string) ([]string, bool)
FormFile(key string) (*multipart.FileHeader, error)
// JSON body
BindJSON(obj any) error
// XML body
BindXML(obj any) error
// RAW body
GetRawData() ([]byte, error)
// Basic informations
Uri() string
Method() string
Host() string
ClientIP() string
// Header
Headers() map[string][]string
Header(key string) (string, bool)
// Cookie
Cookies() map[string]string
Cookie(key string) (string, bool)
}
// {{{ url query
// QueryAll returns all queries in a request URL
func (ctx *Context) QueryAll() url.Values {
if ctx.Request != nil {
return map[string][]string(ctx.Request.URL.Query())
}
return url.Values{}
}
// QueryInt gets an int value from the query request
func (ctx *Context) QueryIntWithDefault(key string, defval int) (int, bool) {
params := ctx.QueryAll()
if vals, ok := params[key]; ok {
if len(vals) > 0 {
return cast.ToInt(vals[0]), true
}
}
return defval, false
}
func (ctx *Context) QueryInt64WithDefault(key string, defval int64) (int64, bool) {
params := ctx.QueryAll()
if vals, ok := params[key]; ok {
if len(vals) > 0 {
return cast.ToInt64(vals[0]), true
}
}
return defval, false
}
func (ctx *Context) QueryBoolWithDefault(key string, defval bool) (bool, bool) {
params := ctx.QueryAll()
if vals, ok := params[key]; ok {
if len(vals) > 0 {
return cast.ToBool(vals[0]), true
}
}
return defval, false
}
func (ctx *Context) QueryFloat32WithDefault(key string, defval float32) (float32, bool) {
params := ctx.QueryAll()
if vals, ok := params[key]; ok {
if len(vals) > 0 {
return cast.ToFloat32(vals[0]), true
}
}
return defval, false
}
func (ctx *Context) QueryFloat64WithDefault(key string, defval float64) (float64, bool) {
params := ctx.QueryAll()
if vals, ok := params[key]; ok {
if len(vals) > 0 {
return cast.ToFloat64(vals[0]), true
}
}
return defval, false
}
// QueryString gets a string value from the query request
func (ctx *Context) QueryStringWithDefault(key string, defval string) (string, bool) {
params := ctx.QueryAll()
if vals, ok := params[key]; ok {
if len(vals) > 0 {
return cast.ToString(vals[0]), true
}
}
return defval, false
}
// QueryArray gets an array of string values from the query request
func (ctx *Context) QueryStringSliceWithDefault(key string, defval []string) ([]string, bool) {
params := ctx.QueryAll()
if vals, ok := params[key]; ok {
return cast.ToStringSlice(vals[0]), true
}
return defval, false
}
// }}}
// {{{ url params
func (ctx *Context) ParamIntWithDefault(key string, def int) (int, bool) {
if val := ctx.Param(key); val != "" {
return cast.ToInt(val), true
}
return def, false
}
func (ctx *Context) ParamInt64WithDefault(key string, def int64) (int64, bool) {
if val := ctx.Param(key); val != "" {
return cast.ToInt64(val), true
}
return def, false
}
func (ctx *Context) ParamFloat64WithDefault(key string, def float64) (float64, bool) {
if val := ctx.Param(key); val != "" {
return cast.ToFloat64(val), true
}
return def, false
}
func (ctx *Context) ParamFloat32WithDefault(key string, def float32) (float32, bool) {
if val := ctx.Param(key); val != "" {
return cast.ToFloat32(val), true
}
return def, false
}
func (ctx *Context) ParamBoolWithDefault(key string, def bool) (bool, bool) {
if val := ctx.Param(key); val != "" {
return cast.ToBool(val), true
}
return def, false
}
func (ctx *Context) ParamStringWithDefault(key string, def string) (string, bool) {
if val := ctx.Param(key); val != "" {
return cast.ToString(val), true
}
return def, false
}
// }}}
// {{{ Post form
// FormAll gets everything from the submitted form
func (ctx *Context) FormAll() url.Values {
if ctx.Request != nil {
_ = ctx.Request.ParseForm()
return ctx.Request.PostForm
}
return url.Values{}
}
// FormInt gets an int value from the submitted form
func (ctx *Context) FormIntWithDefault(key string, defval int) (int, bool) {
params := ctx.FormAll()
if vals, ok := params[key]; ok {
if len(vals) > 0 {
return cast.ToInt(vals[0]), true
}
}
return defval, false
}
func (ctx *Context) FormInt64WithDefault(key string, defval int64) (int64, bool) {
params := ctx.FormAll()
if vals, ok := params[key]; ok {
if len(vals) > 0 {
return cast.ToInt64(vals[0]), true
}
}
return defval, false
}
func (ctx *Context) FormBoolWithDefault(key string, defval bool) (bool, bool) {
params := ctx.FormAll()
if vals, ok := params[key]; ok {
if len(vals) > 0 {
return cast.ToBool(vals[0]), true
}
}
return defval, false
}
func (ctx *Context) FormFloat32WithDefault(key string, defval float32) (float32, bool) {
params := ctx.FormAll()
if vals, ok := params[key]; ok {
if len(vals) > 0 {
return cast.ToFloat32(vals[0]), true
}
}
return defval, false
}
func (ctx *Context) FormFloat64WithDefault(key string, defval float64) (float64, bool) {
params := ctx.FormAll()
if vals, ok := params[key]; ok {
if len(vals) > 0 {
return cast.ToFloat64(vals[0]), true
}
}
return defval, false
}
func (ctx *Context) FormStringWithDefault(key string, defval string) (string, bool) {
params := ctx.FormAll()
if vals, ok := params[key]; ok {
if len(vals) > 0 {
return cast.ToString(vals[0]), true
}
}
return defval, false
}
func (ctx *Context) FormStringSliceWithDefault(key string, defval []string) ([]string, bool) {
params := ctx.FormAll()
if vals, ok := params[key]; ok {
return cast.ToStringSlice(vals[0]), true
}
return defval, false
}
// }}}
// {{{ Basic informations
func (ctx *Context) Uri() string {
return ctx.Request.RequestURI
}
func (ctx *Context) Method() string {
return ctx.Request.Method
}
func (ctx *Context) Host() string {
return ctx.Request.Host
}
// }}}
// {{{ Headers
// Header
func (ctx *Context) Headers() map[string][]string {
return ctx.Request.Header
}
// }}}
// {{{ Cookies
// Cookies gets cookie key-value pairs
func (ctx *Context) Cookies() map[string]string {
cookies := ctx.Request.Cookies()
ret := map[string]string{}
for _, c := range cookies {
ret[c.Name] = c.Value
}
return ret
}
// }}}

78
araneae_response.go Normal file
View File

@ -0,0 +1,78 @@
package gin
import (
"net/http"
)
type IResponse interface {
IJSON(status int, obj any) IResponse
IXML(status int, obj any) IResponse
IHTML(status int, filepath string, obj any) IResponse
IText(status int, format string, values ...any) IResponse
IRedirect(status int, path string) IResponse
ISetHeader(key string, val string) IResponse
ISetCookie(
key string,
val string,
maxAge int,
path, domain string,
secure, httpOnly bool,
) IResponse
ISetStatus(code int) IResponse
// set 200
ISetOKStatus() IResponse
}
func (ctx *Context) IJSON(status int, obj any) IResponse {
ctx.JSON(status, obj)
return ctx
}
func (ctx *Context) IXML(status int, obj any) IResponse {
ctx.XML(status, obj)
return ctx
}
func (ctx *Context) IHTML(status int, filepath string, obj any) IResponse {
ctx.HTML(status, filepath, obj)
return ctx
}
func (ctx *Context) IText(status int, format string, values ...any) IResponse {
ctx.String(status, format, values...)
return ctx
}
func (ctx *Context) IRedirect(status int, path string) IResponse {
ctx.Redirect(status, path)
return ctx
}
func (ctx *Context) ISetHeader(key string, val string) IResponse {
ctx.Header(key, val)
return ctx
}
func (ctx *Context) ISetCookie(
key string,
val string,
maxAge int,
path, domain string,
secure, httpOnly bool,
) IResponse {
ctx.SetCookie(key, val, maxAge, path, domain, secure, httpOnly)
return ctx
}
func (ctx *Context) ISetStatus(code int) IResponse {
ctx.Status(code)
return ctx
}
// set 200
func (ctx *Context) ISetOKStatus() IResponse {
ctx.Status(http.StatusOK)
return ctx
}

View File

@ -11,6 +11,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/ugorji/go/codec"
)
@ -24,7 +25,7 @@ func TestBindingMsgPack(t *testing.T) {
buf := bytes.NewBuffer([]byte{})
assert.NotNil(t, buf)
err := codec.NewEncoder(buf, h).Encode(test)
assert.NoError(t, err)
require.NoError(t, err)
data := buf.Bytes()
@ -41,14 +42,14 @@ func testMsgPackBodyBinding(t *testing.T, b Binding, name, path, badPath, body,
req := requestWithBody("POST", path, body)
req.Header.Add("Content-Type", MIMEMSGPACK)
err := b.Bind(req, &obj)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, "bar", obj.Foo)
obj = FooStruct{}
req = requestWithBody("POST", badPath, badBody)
req.Header.Add("Content-Type", MIMEMSGPACK)
err = MsgPack.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
}
func TestBindingDefaultMsgPack(t *testing.T) {

View File

@ -20,6 +20,7 @@ import (
"github.com/gin-gonic/gin/testdata/protoexample"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
)
@ -175,7 +176,7 @@ func TestBindingJSONNilBody(t *testing.T) {
var obj FooStruct
req, _ := http.NewRequest(http.MethodPost, "/", nil)
err := JSON.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
}
func TestBindingJSON(t *testing.T) {
@ -376,7 +377,7 @@ func TestBindingFormStringSliceMap(t *testing.T) {
req := requestWithBody("POST", "/", "foo=something&foo=bar&hello=world")
req.Header.Add("Content-Type", MIMEPOSTForm)
err := Form.Bind(req, &obj)
assert.NoError(t, err)
require.NoError(t, err)
assert.NotNil(t, obj)
assert.Len(t, obj, 2)
target := map[string][]string{
@ -389,7 +390,7 @@ func TestBindingFormStringSliceMap(t *testing.T) {
req = requestWithBody("POST", "/", "foo=something&foo=bar&hello=world")
req.Header.Add("Content-Type", MIMEPOSTForm)
err = Form.Bind(req, &objInvalid)
assert.Error(t, err)
require.Error(t, err)
}
func TestBindingQuery(t *testing.T) {
@ -428,7 +429,7 @@ func TestBindingQueryStringMap(t *testing.T) {
obj := make(map[string]string)
req := requestWithBody("GET", "/?foo=bar&hello=world", "")
err := b.Bind(req, &obj)
assert.NoError(t, err)
require.NoError(t, err)
assert.NotNil(t, obj)
assert.Len(t, obj, 2)
assert.Equal(t, "bar", obj["foo"])
@ -437,7 +438,7 @@ func TestBindingQueryStringMap(t *testing.T) {
obj = make(map[string]string)
req = requestWithBody("GET", "/?foo=bar&foo=2&hello=world", "") // should pick last
err = b.Bind(req, &obj)
assert.NoError(t, err)
require.NoError(t, err)
assert.NotNil(t, obj)
assert.Len(t, obj, 2)
assert.Equal(t, "2", obj["foo"])
@ -495,28 +496,28 @@ func TestBindingYAMLFail(t *testing.T) {
func createFormPostRequest(t *testing.T) *http.Request {
req, err := http.NewRequest("POST", "/?foo=getfoo&bar=getbar", bytes.NewBufferString("foo=bar&bar=foo"))
assert.NoError(t, err)
require.NoError(t, err)
req.Header.Set("Content-Type", MIMEPOSTForm)
return req
}
func createDefaultFormPostRequest(t *testing.T) *http.Request {
req, err := http.NewRequest("POST", "/?foo=getfoo&bar=getbar", bytes.NewBufferString("foo=bar"))
assert.NoError(t, err)
require.NoError(t, err)
req.Header.Set("Content-Type", MIMEPOSTForm)
return req
}
func createFormPostRequestForMap(t *testing.T) *http.Request {
req, err := http.NewRequest("POST", "/?map_foo=getfoo", bytes.NewBufferString("map_foo={\"bar\":123}"))
assert.NoError(t, err)
require.NoError(t, err)
req.Header.Set("Content-Type", MIMEPOSTForm)
return req
}
func createFormPostRequestForMapFail(t *testing.T) *http.Request {
req, err := http.NewRequest("POST", "/?map_foo=getfoo", bytes.NewBufferString("map_foo=hello"))
assert.NoError(t, err)
require.NoError(t, err)
req.Header.Set("Content-Type", MIMEPOSTForm)
return req
}
@ -527,20 +528,20 @@ func createFormFilesMultipartRequest(t *testing.T) *http.Request {
mw := multipart.NewWriter(body)
defer mw.Close()
assert.NoError(t, mw.SetBoundary(boundary))
assert.NoError(t, mw.WriteField("foo", "bar"))
assert.NoError(t, mw.WriteField("bar", "foo"))
require.NoError(t, mw.SetBoundary(boundary))
require.NoError(t, mw.WriteField("foo", "bar"))
require.NoError(t, mw.WriteField("bar", "foo"))
f, err := os.Open("form.go")
assert.NoError(t, err)
require.NoError(t, err)
defer f.Close()
fw, err1 := mw.CreateFormFile("file", "form.go")
assert.NoError(t, err1)
require.NoError(t, err1)
_, err = io.Copy(fw, f)
assert.NoError(t, err)
require.NoError(t, err)
req, err2 := http.NewRequest("POST", "/?foo=getfoo&bar=getbar", body)
assert.NoError(t, err2)
require.NoError(t, err2)
req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+boundary)
return req
@ -552,20 +553,20 @@ func createFormFilesMultipartRequestFail(t *testing.T) *http.Request {
mw := multipart.NewWriter(body)
defer mw.Close()
assert.NoError(t, mw.SetBoundary(boundary))
assert.NoError(t, mw.WriteField("foo", "bar"))
assert.NoError(t, mw.WriteField("bar", "foo"))
require.NoError(t, mw.SetBoundary(boundary))
require.NoError(t, mw.WriteField("foo", "bar"))
require.NoError(t, mw.WriteField("bar", "foo"))
f, err := os.Open("form.go")
assert.NoError(t, err)
require.NoError(t, err)
defer f.Close()
fw, err1 := mw.CreateFormFile("file_foo", "form_foo.go")
assert.NoError(t, err1)
require.NoError(t, err1)
_, err = io.Copy(fw, f)
assert.NoError(t, err)
require.NoError(t, err)
req, err2 := http.NewRequest("POST", "/?foo=getfoo&bar=getbar", body)
assert.NoError(t, err2)
require.NoError(t, err2)
req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+boundary)
return req
@ -577,11 +578,11 @@ func createFormMultipartRequest(t *testing.T) *http.Request {
mw := multipart.NewWriter(body)
defer mw.Close()
assert.NoError(t, mw.SetBoundary(boundary))
assert.NoError(t, mw.WriteField("foo", "bar"))
assert.NoError(t, mw.WriteField("bar", "foo"))
require.NoError(t, mw.SetBoundary(boundary))
require.NoError(t, mw.WriteField("foo", "bar"))
require.NoError(t, mw.WriteField("bar", "foo"))
req, err := http.NewRequest("POST", "/?foo=getfoo&bar=getbar", body)
assert.NoError(t, err)
require.NoError(t, err)
req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+boundary)
return req
}
@ -592,10 +593,10 @@ func createFormMultipartRequestForMap(t *testing.T) *http.Request {
mw := multipart.NewWriter(body)
defer mw.Close()
assert.NoError(t, mw.SetBoundary(boundary))
assert.NoError(t, mw.WriteField("map_foo", "{\"bar\":123, \"name\":\"thinkerou\", \"pai\": 3.14}"))
require.NoError(t, mw.SetBoundary(boundary))
require.NoError(t, mw.WriteField("map_foo", "{\"bar\":123, \"name\":\"thinkerou\", \"pai\": 3.14}"))
req, err := http.NewRequest("POST", "/?map_foo=getfoo", body)
assert.NoError(t, err)
require.NoError(t, err)
req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+boundary)
return req
}
@ -606,10 +607,10 @@ func createFormMultipartRequestForMapFail(t *testing.T) *http.Request {
mw := multipart.NewWriter(body)
defer mw.Close()
assert.NoError(t, mw.SetBoundary(boundary))
assert.NoError(t, mw.WriteField("map_foo", "3.14"))
require.NoError(t, mw.SetBoundary(boundary))
require.NoError(t, mw.WriteField("map_foo", "3.14"))
req, err := http.NewRequest("POST", "/?map_foo=getfoo", body)
assert.NoError(t, err)
require.NoError(t, err)
req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+boundary)
return req
}
@ -617,7 +618,7 @@ func createFormMultipartRequestForMapFail(t *testing.T) *http.Request {
func TestBindingFormPost(t *testing.T) {
req := createFormPostRequest(t)
var obj FooBarStruct
assert.NoError(t, FormPost.Bind(req, &obj))
require.NoError(t, FormPost.Bind(req, &obj))
assert.Equal(t, "form-urlencoded", FormPost.Name())
assert.Equal(t, "bar", obj.Foo)
@ -627,7 +628,7 @@ func TestBindingFormPost(t *testing.T) {
func TestBindingDefaultValueFormPost(t *testing.T) {
req := createDefaultFormPostRequest(t)
var obj FooDefaultBarStruct
assert.NoError(t, FormPost.Bind(req, &obj))
require.NoError(t, FormPost.Bind(req, &obj))
assert.Equal(t, "bar", obj.Foo)
assert.Equal(t, "hello", obj.Bar)
@ -637,22 +638,22 @@ func TestBindingFormPostForMap(t *testing.T) {
req := createFormPostRequestForMap(t)
var obj FooStructForMapType
err := FormPost.Bind(req, &obj)
assert.NoError(t, err)
assert.Equal(t, float64(123), obj.MapFoo["bar"].(float64))
require.NoError(t, err)
assert.InDelta(t, float64(123), obj.MapFoo["bar"].(float64), 0.01)
}
func TestBindingFormPostForMapFail(t *testing.T) {
req := createFormPostRequestForMapFail(t)
var obj FooStructForMapType
err := FormPost.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
}
func TestBindingFormFilesMultipart(t *testing.T) {
req := createFormFilesMultipartRequest(t)
var obj FooBarFileStruct
err := FormMultipart.Bind(req, &obj)
assert.NoError(t, err)
require.NoError(t, err)
// file from os
f, _ := os.Open("form.go")
@ -664,9 +665,9 @@ func TestBindingFormFilesMultipart(t *testing.T) {
defer mf.Close()
fileExpect, _ := io.ReadAll(mf)
assert.Equal(t, FormMultipart.Name(), "multipart/form-data")
assert.Equal(t, obj.Foo, "bar")
assert.Equal(t, obj.Bar, "foo")
assert.Equal(t, "multipart/form-data", FormMultipart.Name())
assert.Equal(t, "bar", obj.Foo)
assert.Equal(t, "foo", obj.Bar)
assert.Equal(t, fileExpect, fileActual)
}
@ -674,13 +675,13 @@ func TestBindingFormFilesMultipartFail(t *testing.T) {
req := createFormFilesMultipartRequestFail(t)
var obj FooBarFileFailStruct
err := FormMultipart.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
}
func TestBindingFormMultipart(t *testing.T) {
req := createFormMultipartRequest(t)
var obj FooBarStruct
assert.NoError(t, FormMultipart.Bind(req, &obj))
require.NoError(t, FormMultipart.Bind(req, &obj))
assert.Equal(t, "multipart/form-data", FormMultipart.Name())
assert.Equal(t, "bar", obj.Foo)
@ -691,17 +692,17 @@ func TestBindingFormMultipartForMap(t *testing.T) {
req := createFormMultipartRequestForMap(t)
var obj FooStructForMapType
err := FormMultipart.Bind(req, &obj)
assert.NoError(t, err)
assert.Equal(t, float64(123), obj.MapFoo["bar"].(float64))
require.NoError(t, err)
assert.InDelta(t, float64(123), obj.MapFoo["bar"].(float64), 0.01)
assert.Equal(t, "thinkerou", obj.MapFoo["name"].(string))
assert.Equal(t, float64(3.14), obj.MapFoo["pai"].(float64))
assert.InDelta(t, float64(3.14), obj.MapFoo["pai"].(float64), 0.01)
}
func TestBindingFormMultipartForMapFail(t *testing.T) {
req := createFormMultipartRequestForMapFail(t)
var obj FooStructForMapType
err := FormMultipart.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
}
func TestBindingProtoBuf(t *testing.T) {
@ -732,7 +733,7 @@ func TestValidationFails(t *testing.T) {
var obj FooStruct
req := requestWithBody("POST", "/", `{"bar": "foo"}`)
err := JSON.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
}
func TestValidationDisabled(t *testing.T) {
@ -743,7 +744,7 @@ func TestValidationDisabled(t *testing.T) {
var obj FooStruct
req := requestWithBody("POST", "/", `{"bar": "foo"}`)
err := JSON.Bind(req, &obj)
assert.NoError(t, err)
require.NoError(t, err)
}
func TestRequiredSucceeds(t *testing.T) {
@ -754,7 +755,7 @@ func TestRequiredSucceeds(t *testing.T) {
var obj HogeStruct
req := requestWithBody("POST", "/", `{"hoge": 0}`)
err := JSON.Bind(req, &obj)
assert.NoError(t, err)
require.NoError(t, err)
}
func TestRequiredFails(t *testing.T) {
@ -765,7 +766,7 @@ func TestRequiredFails(t *testing.T) {
var obj HogeStruct
req := requestWithBody("POST", "/", `{"boen": 0}`)
err := JSON.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
}
func TestHeaderBinding(t *testing.T) {
@ -779,7 +780,7 @@ func TestHeaderBinding(t *testing.T) {
var theader tHeader
req := requestWithBody("GET", "/", "")
req.Header.Add("limit", "1000")
assert.NoError(t, h.Bind(req, &theader))
require.NoError(t, h.Bind(req, &theader))
assert.Equal(t, 1000, theader.Limit)
req = requestWithBody("GET", "/", "")
@ -790,7 +791,7 @@ func TestHeaderBinding(t *testing.T) {
}
err := h.Bind(req, &failStruct{})
assert.Error(t, err)
require.Error(t, err)
}
func TestUriBinding(t *testing.T) {
@ -803,14 +804,14 @@ func TestUriBinding(t *testing.T) {
var tag Tag
m := make(map[string][]string)
m["name"] = []string{"thinkerou"}
assert.NoError(t, b.BindUri(m, &tag))
require.NoError(t, b.BindUri(m, &tag))
assert.Equal(t, "thinkerou", tag.Name)
type NotSupportStruct struct {
Name map[string]any `uri:"name"`
}
var not NotSupportStruct
assert.Error(t, b.BindUri(m, &not))
require.Error(t, b.BindUri(m, &not))
assert.Equal(t, map[string]any(nil), not.Name)
}
@ -831,9 +832,9 @@ func TestUriInnerBinding(t *testing.T) {
}
var tag Tag
assert.NoError(t, Uri.BindUri(m, &tag))
assert.Equal(t, tag.Name, expectedName)
assert.Equal(t, tag.S.Age, expectedAge)
require.NoError(t, Uri.BindUri(m, &tag))
assert.Equal(t, expectedName, tag.Name)
assert.Equal(t, expectedAge, tag.S.Age)
}
func testFormBindingEmbeddedStruct(t *testing.T, method, path, badPath, body, badBody string) {
@ -846,7 +847,7 @@ func testFormBindingEmbeddedStruct(t *testing.T, method, path, badPath, body, ba
req.Header.Add("Content-Type", MIMEPOSTForm)
}
err := b.Bind(req, &obj)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, 1, obj.Page)
assert.Equal(t, 2, obj.Size)
assert.Equal(t, "test-appkey", obj.Appkey)
@ -862,14 +863,14 @@ func testFormBinding(t *testing.T, method, path, badPath, body, badBody string)
req.Header.Add("Content-Type", MIMEPOSTForm)
}
err := b.Bind(req, &obj)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, "bar", obj.Foo)
assert.Equal(t, "foo", obj.Bar)
obj = FooBarStruct{}
req = requestWithBody(method, badPath, badBody)
err = JSON.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
}
func testFormBindingDefaultValue(t *testing.T, method, path, badPath, body, badBody string) {
@ -882,14 +883,14 @@ func testFormBindingDefaultValue(t *testing.T, method, path, badPath, body, badB
req.Header.Add("Content-Type", MIMEPOSTForm)
}
err := b.Bind(req, &obj)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, "bar", obj.Foo)
assert.Equal(t, "hello", obj.Bar)
obj = FooDefaultBarStruct{}
req = requestWithBody(method, badPath, badBody)
err = JSON.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
}
func TestFormBindingFail(t *testing.T) {
@ -899,18 +900,18 @@ func TestFormBindingFail(t *testing.T) {
obj := FooBarStruct{}
req, _ := http.NewRequest("POST", "/", nil)
err := b.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
}
func TestFormBindingMultipartFail(t *testing.T) {
obj := FooBarStruct{}
req, err := http.NewRequest("POST", "/", strings.NewReader("foo=bar"))
assert.NoError(t, err)
require.NoError(t, err)
req.Header.Set("Content-Type", MIMEMultipartPOSTForm+";boundary=testboundary")
_, err = req.MultipartReader()
assert.NoError(t, err)
require.NoError(t, err)
err = Form.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
}
func TestFormPostBindingFail(t *testing.T) {
@ -920,7 +921,7 @@ func TestFormPostBindingFail(t *testing.T) {
obj := FooBarStruct{}
req, _ := http.NewRequest("POST", "/", nil)
err := b.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
}
func TestFormMultipartBindingFail(t *testing.T) {
@ -930,7 +931,7 @@ func TestFormMultipartBindingFail(t *testing.T) {
obj := FooBarStruct{}
req, _ := http.NewRequest("POST", "/", nil)
err := b.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
}
func testFormBindingForTime(t *testing.T, method, path, badPath, body, badBody string) {
@ -944,7 +945,7 @@ func testFormBindingForTime(t *testing.T, method, path, badPath, body, badBody s
}
err := b.Bind(req, &obj)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, int64(1510675200), obj.TimeFoo.Unix())
assert.Equal(t, "Asia/Chongqing", obj.TimeFoo.Location().String())
assert.Equal(t, int64(-62135596800), obj.TimeBar.Unix())
@ -955,7 +956,7 @@ func testFormBindingForTime(t *testing.T, method, path, badPath, body, badBody s
obj = FooBarStructForTimeType{}
req = requestWithBody(method, badPath, badBody)
err = JSON.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
}
func testFormBindingForTimeNotUnixFormat(t *testing.T, method, path, badPath, body, badBody string) {
@ -968,12 +969,12 @@ func testFormBindingForTimeNotUnixFormat(t *testing.T, method, path, badPath, bo
req.Header.Add("Content-Type", MIMEPOSTForm)
}
err := b.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
obj = FooStructForTimeTypeNotUnixFormat{}
req = requestWithBody(method, badPath, badBody)
err = JSON.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
}
func testFormBindingForTimeNotFormat(t *testing.T, method, path, badPath, body, badBody string) {
@ -986,12 +987,12 @@ func testFormBindingForTimeNotFormat(t *testing.T, method, path, badPath, body,
req.Header.Add("Content-Type", MIMEPOSTForm)
}
err := b.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
obj = FooStructForTimeTypeNotFormat{}
req = requestWithBody(method, badPath, badBody)
err = JSON.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
}
func testFormBindingForTimeFailFormat(t *testing.T, method, path, badPath, body, badBody string) {
@ -1004,12 +1005,12 @@ func testFormBindingForTimeFailFormat(t *testing.T, method, path, badPath, body,
req.Header.Add("Content-Type", MIMEPOSTForm)
}
err := b.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
obj = FooStructForTimeTypeFailFormat{}
req = requestWithBody(method, badPath, badBody)
err = JSON.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
}
func testFormBindingForTimeFailLocation(t *testing.T, method, path, badPath, body, badBody string) {
@ -1022,12 +1023,12 @@ func testFormBindingForTimeFailLocation(t *testing.T, method, path, badPath, bod
req.Header.Add("Content-Type", MIMEPOSTForm)
}
err := b.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
obj = FooStructForTimeTypeFailLocation{}
req = requestWithBody(method, badPath, badBody)
err = JSON.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
}
func testFormBindingIgnoreField(t *testing.T, method, path, badPath, body, badBody string) {
@ -1040,7 +1041,7 @@ func testFormBindingIgnoreField(t *testing.T, method, path, badPath, body, badBo
req.Header.Add("Content-Type", MIMEPOSTForm)
}
err := b.Bind(req, &obj)
assert.NoError(t, err)
require.NoError(t, err)
assert.Nil(t, obj.Foo)
}
@ -1055,13 +1056,13 @@ func testFormBindingInvalidName(t *testing.T, method, path, badPath, body, badBo
req.Header.Add("Content-Type", MIMEPOSTForm)
}
err := b.Bind(req, &obj)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, "", obj.TestName)
obj = InvalidNameType{}
req = requestWithBody(method, badPath, badBody)
err = JSON.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
}
func testFormBindingInvalidName2(t *testing.T, method, path, badPath, body, badBody string) {
@ -1074,12 +1075,12 @@ func testFormBindingInvalidName2(t *testing.T, method, path, badPath, body, badB
req.Header.Add("Content-Type", MIMEPOSTForm)
}
err := b.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
obj = InvalidNameMapType{}
req = requestWithBody(method, badPath, badBody)
err = JSON.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
}
func testFormBindingForType(t *testing.T, method, path, badPath, body, badBody string, typ string) {
@ -1094,17 +1095,17 @@ func testFormBindingForType(t *testing.T, method, path, badPath, body, badBody s
case "Slice":
obj := FooStructForSliceType{}
err := b.Bind(req, &obj)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, []int{1, 2}, obj.SliceFoo)
obj = FooStructForSliceType{}
req = requestWithBody(method, badPath, badBody)
err = JSON.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
case "Struct":
obj := FooStructForStructType{}
err := b.Bind(req, &obj)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t,
struct {
Idx int "form:\"idx\""
@ -1113,7 +1114,7 @@ func testFormBindingForType(t *testing.T, method, path, badPath, body, badBody s
case "StructPointer":
obj := FooStructForStructPointerType{}
err := b.Bind(req, &obj)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t,
struct {
Name string "form:\"name\""
@ -1122,33 +1123,33 @@ func testFormBindingForType(t *testing.T, method, path, badPath, body, badBody s
case "Map":
obj := FooStructForMapType{}
err := b.Bind(req, &obj)
assert.NoError(t, err)
assert.Equal(t, float64(123), obj.MapFoo["bar"].(float64))
require.NoError(t, err)
assert.InDelta(t, float64(123), obj.MapFoo["bar"].(float64), 0.01)
case "SliceMap":
obj := FooStructForSliceMapType{}
err := b.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
case "Ptr":
obj := FooStructForStringPtrType{}
err := b.Bind(req, &obj)
assert.NoError(t, err)
require.NoError(t, err)
assert.Nil(t, obj.PtrFoo)
assert.Equal(t, "test", *obj.PtrBar)
obj = FooStructForStringPtrType{}
obj.PtrBar = new(string)
err = b.Bind(req, &obj)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, "test", *obj.PtrBar)
objErr := FooStructForMapPtrType{}
err = b.Bind(req, &objErr)
assert.Error(t, err)
require.Error(t, err)
obj = FooStructForStringPtrType{}
req = requestWithBody(method, badPath, badBody)
err = b.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
}
}
@ -1162,7 +1163,7 @@ func testQueryBinding(t *testing.T, method, path, badPath, body, badBody string)
req.Header.Add("Content-Type", MIMEPOSTForm)
}
err := b.Bind(req, &obj)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, "bar", obj.Foo)
assert.Equal(t, "foo", obj.Bar)
}
@ -1177,7 +1178,7 @@ func testQueryBindingFail(t *testing.T, method, path, badPath, body, badBody str
req.Header.Add("Content-Type", MIMEPOSTForm)
}
err := b.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
}
func testQueryBindingBoolFail(t *testing.T, method, path, badPath, body, badBody string) {
@ -1190,7 +1191,7 @@ func testQueryBindingBoolFail(t *testing.T, method, path, badPath, body, badBody
req.Header.Add("Content-Type", MIMEPOSTForm)
}
err := b.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
}
func testBodyBinding(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
@ -1199,13 +1200,13 @@ func testBodyBinding(t *testing.T, b Binding, name, path, badPath, body, badBody
obj := FooStruct{}
req := requestWithBody("POST", path, body)
err := b.Bind(req, &obj)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, "bar", obj.Foo)
obj = FooStruct{}
req = requestWithBody("POST", badPath, badBody)
err = JSON.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
}
func testBodyBindingSlice(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
@ -1214,12 +1215,12 @@ func testBodyBindingSlice(t *testing.T, b Binding, name, path, badPath, body, ba
var obj1 []FooStruct
req := requestWithBody("POST", path, body)
err := b.Bind(req, &obj1)
assert.NoError(t, err)
require.NoError(t, err)
var obj2 []FooStruct
req = requestWithBody("POST", badPath, badBody)
err = JSON.Bind(req, &obj2)
assert.Error(t, err)
require.Error(t, err)
}
func testBodyBindingStringMap(t *testing.T, b Binding, path, badPath, body, badBody string) {
@ -1229,7 +1230,7 @@ func testBodyBindingStringMap(t *testing.T, b Binding, path, badPath, body, badB
req.Header.Add("Content-Type", MIMEPOSTForm)
}
err := b.Bind(req, &obj)
assert.NoError(t, err)
require.NoError(t, err)
assert.NotNil(t, obj)
assert.Len(t, obj, 2)
assert.Equal(t, "bar", obj["foo"])
@ -1239,13 +1240,13 @@ func testBodyBindingStringMap(t *testing.T, b Binding, path, badPath, body, badB
obj = make(map[string]string)
req = requestWithBody("POST", badPath, badBody)
err = b.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
}
objInt := make(map[string]int)
req = requestWithBody("POST", path, body)
err = b.Bind(req, &objInt)
assert.Error(t, err)
require.Error(t, err)
}
func testBodyBindingUseNumber(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
@ -1255,16 +1256,16 @@ func testBodyBindingUseNumber(t *testing.T, b Binding, name, path, badPath, body
req := requestWithBody("POST", path, body)
EnableDecoderUseNumber = true
err := b.Bind(req, &obj)
assert.NoError(t, err)
require.NoError(t, err)
// we hope it is int64(123)
v, e := obj.Foo.(json.Number).Int64()
assert.NoError(t, e)
require.NoError(t, e)
assert.Equal(t, int64(123), v)
obj = FooStructUseNumber{}
req = requestWithBody("POST", badPath, badBody)
err = JSON.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
}
func testBodyBindingUseNumber2(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
@ -1274,15 +1275,15 @@ func testBodyBindingUseNumber2(t *testing.T, b Binding, name, path, badPath, bod
req := requestWithBody("POST", path, body)
EnableDecoderUseNumber = false
err := b.Bind(req, &obj)
assert.NoError(t, err)
require.NoError(t, err)
// it will return float64(123) if not use EnableDecoderUseNumber
// maybe it is not hoped
assert.Equal(t, float64(123), obj.Foo)
assert.InDelta(t, float64(123), obj.Foo, 0.01)
obj = FooStructUseNumber{}
req = requestWithBody("POST", badPath, badBody)
err = JSON.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
}
func testBodyBindingDisallowUnknownFields(t *testing.T, b Binding, path, badPath, body, badBody string) {
@ -1294,13 +1295,13 @@ func testBodyBindingDisallowUnknownFields(t *testing.T, b Binding, path, badPath
obj := FooStructDisallowUnknownFields{}
req := requestWithBody("POST", path, body)
err := b.Bind(req, &obj)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, "bar", obj.Foo)
obj = FooStructDisallowUnknownFields{}
req = requestWithBody("POST", badPath, badBody)
err = JSON.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
assert.Contains(t, err.Error(), "what")
}
@ -1310,13 +1311,13 @@ func testBodyBindingFail(t *testing.T, b Binding, name, path, badPath, body, bad
obj := FooStruct{}
req := requestWithBody("POST", path, body)
err := b.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
assert.Equal(t, "", obj.Foo)
obj = FooStruct{}
req = requestWithBody("POST", badPath, badBody)
err = JSON.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
}
func testProtoBodyBinding(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
@ -1326,14 +1327,14 @@ func testProtoBodyBinding(t *testing.T, b Binding, name, path, badPath, body, ba
req := requestWithBody("POST", path, body)
req.Header.Add("Content-Type", MIMEPROTOBUF)
err := b.Bind(req, &obj)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, "yes", *obj.Label)
obj = protoexample.Test{}
req = requestWithBody("POST", badPath, badBody)
req.Header.Add("Content-Type", MIMEPROTOBUF)
err = ProtoBuf.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
}
type hook struct{}
@ -1358,28 +1359,28 @@ func TestPlainBinding(t *testing.T) {
var s string
req := requestWithBody("POST", "/", "test string")
assert.NoError(t, p.Bind(req, &s))
assert.Equal(t, s, "test string")
require.NoError(t, p.Bind(req, &s))
assert.Equal(t, "test string", s)
var bs []byte
req = requestWithBody("POST", "/", "test []byte")
assert.NoError(t, p.Bind(req, &bs))
require.NoError(t, p.Bind(req, &bs))
assert.Equal(t, bs, []byte("test []byte"))
var i int
req = requestWithBody("POST", "/", "test fail")
assert.Error(t, p.Bind(req, &i))
require.Error(t, p.Bind(req, &i))
req = requestWithBody("POST", "/", "")
req.Body = &failRead{}
assert.Error(t, p.Bind(req, &s))
require.Error(t, p.Bind(req, &s))
req = requestWithBody("POST", "/", "")
assert.Nil(t, p.Bind(req, nil))
require.NoError(t, p.Bind(req, nil))
var ptr *string
req = requestWithBody("POST", "/", "")
assert.Nil(t, p.Bind(req, ptr))
require.NoError(t, p.Bind(req, ptr))
}
func testProtoBodyBindingFail(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
@ -1391,20 +1392,20 @@ func testProtoBodyBindingFail(t *testing.T, b Binding, name, path, badPath, body
req.Body = io.NopCloser(&hook{})
req.Header.Add("Content-Type", MIMEPROTOBUF)
err := b.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
invalidobj := FooStruct{}
req.Body = io.NopCloser(strings.NewReader(`{"msg":"hello"}`))
req.Header.Add("Content-Type", MIMEPROTOBUF)
err = b.Bind(req, &invalidobj)
assert.Error(t, err)
assert.Equal(t, err.Error(), "obj is not ProtoMessage")
require.Error(t, err)
assert.Equal(t, "obj is not ProtoMessage", err.Error())
obj = protoexample.Test{}
req = requestWithBody("POST", badPath, badBody)
req.Header.Add("Content-Type", MIMEPROTOBUF)
err = ProtoBuf.Bind(req, &obj)
assert.Error(t, err)
require.Error(t, err)
}
func requestWithBody(method, path, body string) (req *http.Request) {

View File

@ -159,6 +159,14 @@ func tryToSetValue(value reflect.Value, field reflect.StructField, setter setter
if k, v := head(opt, "="); k == "default" {
setOpt.isDefaultExists = true
setOpt.defaultValue = v
// convert semicolon-separated default values to csv-separated values for processing in setByForm
if field.Type.Kind() == reflect.Slice || field.Type.Kind() == reflect.Array {
cfTag := field.Tag.Get("collection_format")
if cfTag == "" || cfTag == "multi" || cfTag == "csv" {
setOpt.defaultValue = strings.ReplaceAll(v, ";", ",")
}
}
}
}
@ -182,6 +190,38 @@ func trySetCustom(val string, value reflect.Value) (isSet bool, err error) {
return false, nil
}
func trySplit(vs []string, field reflect.StructField) (newVs []string, err error) {
cfTag := field.Tag.Get("collection_format")
if cfTag == "" || cfTag == "multi" {
return vs, nil
}
var sep string
switch cfTag {
case "csv":
sep = ","
case "ssv":
sep = " "
case "tsv":
sep = "\t"
case "pipes":
sep = "|"
default:
return vs, fmt.Errorf("%s is not supported in the collection_format. (csv, ssv, pipes)", cfTag)
}
totalLength := 0
for _, v := range vs {
totalLength += strings.Count(v, sep) + 1
}
newVs = make([]string, 0, totalLength)
for _, v := range vs {
newVs = append(newVs, strings.Split(v, sep)...)
}
return newVs, nil
}
func setByForm(value reflect.Value, field reflect.StructField, form map[string][]string, tagValue string, opt setOptions) (isSet bool, err error) {
vs, ok := form[tagValue]
if !ok && !opt.isDefaultExists {
@ -192,22 +232,42 @@ func setByForm(value reflect.Value, field reflect.StructField, form map[string][
case reflect.Slice:
if !ok {
vs = []string{opt.defaultValue}
// pre-process the default value for multi if present
cfTag := field.Tag.Get("collection_format")
if cfTag == "" || cfTag == "multi" {
vs = strings.Split(opt.defaultValue, ",")
}
}
if ok, err = trySetCustom(vs[0], value); ok {
return ok, err
}
if vs, err = trySplit(vs, field); err != nil {
return false, err
}
return true, setSlice(vs, value, field)
case reflect.Array:
if !ok {
vs = []string{opt.defaultValue}
// pre-process the default value for multi if present
cfTag := field.Tag.Get("collection_format")
if cfTag == "" || cfTag == "multi" {
vs = strings.Split(opt.defaultValue, ",")
}
}
if ok, err = trySetCustom(vs[0], value); ok {
return ok, err
}
if vs, err = trySplit(vs, field); err != nil {
return false, err
}
if len(vs) != value.Len() {
return false, fmt.Errorf("%q is not valid value for %s", vs, value.Type().String())
}
@ -221,6 +281,9 @@ func setByForm(value reflect.Value, field reflect.StructField, form map[string][
if len(vs) > 0 {
val = vs[0]
if val == "" {
val = opt.defaultValue
}
}
if ok, err := trySetCustom(val, value); ok {
return ok, err

View File

@ -15,6 +15,7 @@ import (
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestMappingBaseTypes(t *testing.T) {
@ -59,7 +60,7 @@ func TestMappingBaseTypes(t *testing.T) {
field := val.Elem().Type().Field(0)
_, err := mapping(val, emptyField, formSource{field.Name: {tt.form}}, "form")
assert.NoError(t, err, testName)
require.NoError(t, err, testName)
actual := val.Elem().Field(0).Interface()
assert.Equal(t, tt.expect, actual, testName)
@ -68,13 +69,15 @@ func TestMappingBaseTypes(t *testing.T) {
func TestMappingDefault(t *testing.T) {
var s struct {
Str string `form:",default=defaultVal"`
Int int `form:",default=9"`
Slice []int `form:",default=9"`
Array [1]int `form:",default=9"`
}
err := mappingByPtr(&s, formSource{}, "form")
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, "defaultVal", s.Str)
assert.Equal(t, 9, s.Int)
assert.Equal(t, []int{9}, s.Slice)
assert.Equal(t, [1]int{9}, s.Array)
@ -85,7 +88,7 @@ func TestMappingSkipField(t *testing.T) {
A int
}
err := mappingByPtr(&s, formSource{}, "form")
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, 0, s.A)
}
@ -96,7 +99,7 @@ func TestMappingIgnoreField(t *testing.T) {
B int `form:"-"`
}
err := mappingByPtr(&s, formSource{"A": {"9"}, "B": {"9"}}, "form")
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, 9, s.A)
assert.Equal(t, 0, s.B)
@ -108,7 +111,7 @@ func TestMappingUnexportedField(t *testing.T) {
b int `form:"b"`
}
err := mappingByPtr(&s, formSource{"a": {"9"}, "b": {"9"}}, "form")
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, 9, s.A)
assert.Equal(t, 0, s.b)
@ -119,7 +122,7 @@ func TestMappingPrivateField(t *testing.T) {
f int `form:"field"`
}
err := mappingByPtr(&s, formSource{"field": {"6"}}, "form")
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, 0, s.f)
}
@ -129,7 +132,7 @@ func TestMappingUnknownFieldType(t *testing.T) {
}
err := mappingByPtr(&s, formSource{"U": {"unknown"}}, "form")
assert.Error(t, err)
require.Error(t, err)
assert.Equal(t, errUnknownType, err)
}
@ -138,7 +141,7 @@ func TestMappingURI(t *testing.T) {
F int `uri:"field"`
}
err := mapURI(&s, map[string][]string{"field": {"6"}})
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, 6, s.F)
}
@ -147,16 +150,34 @@ func TestMappingForm(t *testing.T) {
F int `form:"field"`
}
err := mapForm(&s, map[string][]string{"field": {"6"}})
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, 6, s.F)
}
func TestMappingFormFieldNotSent(t *testing.T) {
var s struct {
F string `form:"field,default=defVal"`
}
err := mapForm(&s, map[string][]string{})
require.NoError(t, err)
assert.Equal(t, "defVal", s.F)
}
func TestMappingFormWithEmptyToDefault(t *testing.T) {
var s struct {
F string `form:"field,default=DefVal"`
}
err := mapForm(&s, map[string][]string{"field": {""}})
require.NoError(t, err)
assert.Equal(t, "DefVal", s.F)
}
func TestMapFormWithTag(t *testing.T) {
var s struct {
F int `externalTag:"field"`
}
err := MapFormWithTag(&s, map[string][]string{"field": {"6"}}, "externalTag")
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, 6, s.F)
}
@ -171,7 +192,7 @@ func TestMappingTime(t *testing.T) {
var err error
time.Local, err = time.LoadLocation("Europe/Berlin")
assert.NoError(t, err)
require.NoError(t, err)
err = mapForm(&s, map[string][]string{
"Time": {"2019-01-20T16:02:58Z"},
@ -180,7 +201,7 @@ func TestMappingTime(t *testing.T) {
"CSTTime": {"2019-01-20"},
"UTCTime": {"2019-01-20"},
})
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, "2019-01-20 16:02:58 +0000 UTC", s.Time.String())
assert.Equal(t, "2019-01-20 00:00:00 +0100 CET", s.LocalTime.String())
@ -195,14 +216,14 @@ func TestMappingTime(t *testing.T) {
Time time.Time `time_location:"wrong"`
}
err = mapForm(&wrongLoc, map[string][]string{"Time": {"2019-01-20T16:02:58Z"}})
assert.Error(t, err)
require.Error(t, err)
// wrong time value
var wrongTime struct {
Time time.Time
}
err = mapForm(&wrongTime, map[string][]string{"Time": {"wrong"}})
assert.Error(t, err)
require.Error(t, err)
}
func TestMappingTimeDuration(t *testing.T) {
@ -212,12 +233,12 @@ func TestMappingTimeDuration(t *testing.T) {
// ok
err := mappingByPtr(&s, formSource{"D": {"5s"}}, "form")
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, 5*time.Second, s.D)
// error
err = mappingByPtr(&s, formSource{"D": {"wrong"}}, "form")
assert.Error(t, err)
require.Error(t, err)
}
func TestMappingSlice(t *testing.T) {
@ -227,17 +248,17 @@ func TestMappingSlice(t *testing.T) {
// default value
err := mappingByPtr(&s, formSource{}, "form")
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, []int{9}, s.Slice)
// ok
err = mappingByPtr(&s, formSource{"slice": {"3", "4"}}, "form")
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, []int{3, 4}, s.Slice)
// error
err = mappingByPtr(&s, formSource{"slice": {"wrong"}}, "form")
assert.Error(t, err)
require.Error(t, err)
}
func TestMappingArray(t *testing.T) {
@ -247,20 +268,125 @@ func TestMappingArray(t *testing.T) {
// wrong default
err := mappingByPtr(&s, formSource{}, "form")
assert.Error(t, err)
require.Error(t, err)
// ok
err = mappingByPtr(&s, formSource{"array": {"3", "4"}}, "form")
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, [2]int{3, 4}, s.Array)
// error - not enough vals
err = mappingByPtr(&s, formSource{"array": {"3"}}, "form")
assert.Error(t, err)
require.Error(t, err)
// error - wrong value
err = mappingByPtr(&s, formSource{"array": {"wrong"}}, "form")
assert.Error(t, err)
require.Error(t, err)
}
func TestMappingCollectionFormat(t *testing.T) {
var s struct {
SliceMulti []int `form:"slice_multi" collection_format:"multi"`
SliceCsv []int `form:"slice_csv" collection_format:"csv"`
SliceSsv []int `form:"slice_ssv" collection_format:"ssv"`
SliceTsv []int `form:"slice_tsv" collection_format:"tsv"`
SlicePipes []int `form:"slice_pipes" collection_format:"pipes"`
ArrayMulti [2]int `form:"array_multi" collection_format:"multi"`
ArrayCsv [2]int `form:"array_csv" collection_format:"csv"`
ArraySsv [2]int `form:"array_ssv" collection_format:"ssv"`
ArrayTsv [2]int `form:"array_tsv" collection_format:"tsv"`
ArrayPipes [2]int `form:"array_pipes" collection_format:"pipes"`
}
err := mappingByPtr(&s, formSource{
"slice_multi": {"1", "2"},
"slice_csv": {"1,2"},
"slice_ssv": {"1 2"},
"slice_tsv": {"1 2"},
"slice_pipes": {"1|2"},
"array_multi": {"1", "2"},
"array_csv": {"1,2"},
"array_ssv": {"1 2"},
"array_tsv": {"1 2"},
"array_pipes": {"1|2"},
}, "form")
require.NoError(t, err)
assert.Equal(t, []int{1, 2}, s.SliceMulti)
assert.Equal(t, []int{1, 2}, s.SliceCsv)
assert.Equal(t, []int{1, 2}, s.SliceSsv)
assert.Equal(t, []int{1, 2}, s.SliceTsv)
assert.Equal(t, []int{1, 2}, s.SlicePipes)
assert.Equal(t, [2]int{1, 2}, s.ArrayMulti)
assert.Equal(t, [2]int{1, 2}, s.ArrayCsv)
assert.Equal(t, [2]int{1, 2}, s.ArraySsv)
assert.Equal(t, [2]int{1, 2}, s.ArrayTsv)
assert.Equal(t, [2]int{1, 2}, s.ArrayPipes)
}
func TestMappingCollectionFormatInvalid(t *testing.T) {
var s struct {
SliceCsv []int `form:"slice_csv" collection_format:"xxx"`
}
err := mappingByPtr(&s, formSource{
"slice_csv": {"1,2"},
}, "form")
require.Error(t, err)
var s2 struct {
ArrayCsv [2]int `form:"array_csv" collection_format:"xxx"`
}
err = mappingByPtr(&s2, formSource{
"array_csv": {"1,2"},
}, "form")
require.Error(t, err)
}
func TestMappingMultipleDefaultWithCollectionFormat(t *testing.T) {
var s struct {
SliceMulti []int `form:",default=1;2;3" collection_format:"multi"`
SliceCsv []int `form:",default=1;2;3" collection_format:"csv"`
SliceSsv []int `form:",default=1 2 3" collection_format:"ssv"`
SliceTsv []int `form:",default=1\t2\t3" collection_format:"tsv"`
SlicePipes []int `form:",default=1|2|3" collection_format:"pipes"`
ArrayMulti [2]int `form:",default=1;2" collection_format:"multi"`
ArrayCsv [2]int `form:",default=1;2" collection_format:"csv"`
ArraySsv [2]int `form:",default=1 2" collection_format:"ssv"`
ArrayTsv [2]int `form:",default=1\t2" collection_format:"tsv"`
ArrayPipes [2]int `form:",default=1|2" collection_format:"pipes"`
SliceStringMulti []string `form:",default=1;2;3" collection_format:"multi"`
SliceStringCsv []string `form:",default=1;2;3" collection_format:"csv"`
SliceStringSsv []string `form:",default=1 2 3" collection_format:"ssv"`
SliceStringTsv []string `form:",default=1\t2\t3" collection_format:"tsv"`
SliceStringPipes []string `form:",default=1|2|3" collection_format:"pipes"`
ArrayStringMulti [2]string `form:",default=1;2" collection_format:"multi"`
ArrayStringCsv [2]string `form:",default=1;2" collection_format:"csv"`
ArrayStringSsv [2]string `form:",default=1 2" collection_format:"ssv"`
ArrayStringTsv [2]string `form:",default=1\t2" collection_format:"tsv"`
ArrayStringPipes [2]string `form:",default=1|2" collection_format:"pipes"`
}
err := mappingByPtr(&s, formSource{}, "form")
require.NoError(t, err)
assert.Equal(t, []int{1, 2, 3}, s.SliceMulti)
assert.Equal(t, []int{1, 2, 3}, s.SliceCsv)
assert.Equal(t, []int{1, 2, 3}, s.SliceSsv)
assert.Equal(t, []int{1, 2, 3}, s.SliceTsv)
assert.Equal(t, []int{1, 2, 3}, s.SlicePipes)
assert.Equal(t, [2]int{1, 2}, s.ArrayMulti)
assert.Equal(t, [2]int{1, 2}, s.ArrayCsv)
assert.Equal(t, [2]int{1, 2}, s.ArraySsv)
assert.Equal(t, [2]int{1, 2}, s.ArrayTsv)
assert.Equal(t, [2]int{1, 2}, s.ArrayPipes)
assert.Equal(t, []string{"1", "2", "3"}, s.SliceStringMulti)
assert.Equal(t, []string{"1", "2", "3"}, s.SliceStringCsv)
assert.Equal(t, []string{"1", "2", "3"}, s.SliceStringSsv)
assert.Equal(t, []string{"1", "2", "3"}, s.SliceStringTsv)
assert.Equal(t, []string{"1", "2", "3"}, s.SliceStringPipes)
assert.Equal(t, [2]string{"1", "2"}, s.ArrayStringMulti)
assert.Equal(t, [2]string{"1", "2"}, s.ArrayStringCsv)
assert.Equal(t, [2]string{"1", "2"}, s.ArrayStringSsv)
assert.Equal(t, [2]string{"1", "2"}, s.ArrayStringTsv)
assert.Equal(t, [2]string{"1", "2"}, s.ArrayStringPipes)
}
func TestMappingStructField(t *testing.T) {
@ -271,7 +397,7 @@ func TestMappingStructField(t *testing.T) {
}
err := mappingByPtr(&s, formSource{"J": {`{"I": 9}`}}, "form")
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, 9, s.J.I)
}
@ -289,20 +415,20 @@ func TestMappingPtrField(t *testing.T) {
// With 0 items.
var req0 ptrRequest
err = mappingByPtr(&req0, formSource{}, "form")
assert.NoError(t, err)
require.NoError(t, err)
assert.Empty(t, req0.Items)
// With 1 item.
var req1 ptrRequest
err = mappingByPtr(&req1, formSource{"items": {`{"key": 1}`}}, "form")
assert.NoError(t, err)
require.NoError(t, err)
assert.Len(t, req1.Items, 1)
assert.EqualValues(t, 1, req1.Items[0].Key)
// With 2 items.
var req2 ptrRequest
err = mappingByPtr(&req2, formSource{"items": {`{"key": 1}`, `{"key": 2}`}}, "form")
assert.NoError(t, err)
require.NoError(t, err)
assert.Len(t, req2.Items, 2)
assert.EqualValues(t, 1, req2.Items[0].Key)
assert.EqualValues(t, 2, req2.Items[1].Key)
@ -314,7 +440,7 @@ func TestMappingMapField(t *testing.T) {
}
err := mappingByPtr(&s, formSource{"M": {`{"one": 1}`}}, "form")
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, map[string]int{"one": 1}, s.M)
}
@ -325,7 +451,7 @@ func TestMappingIgnoredCircularRef(t *testing.T) {
var s S
err := mappingByPtr(&s, formSource{}, "form")
assert.NoError(t, err)
require.NoError(t, err)
}
type customUnmarshalParamHex int
@ -344,7 +470,7 @@ func TestMappingCustomUnmarshalParamHexWithFormTag(t *testing.T) {
Foo customUnmarshalParamHex `form:"foo"`
}
err := mappingByPtr(&s, formSource{"foo": {`f5`}}, "form")
assert.NoError(t, err)
require.NoError(t, err)
assert.EqualValues(t, 245, s.Foo)
}
@ -354,7 +480,7 @@ func TestMappingCustomUnmarshalParamHexWithURITag(t *testing.T) {
Foo customUnmarshalParamHex `uri:"foo"`
}
err := mappingByPtr(&s, formSource{"foo": {`f5`}}, "uri")
assert.NoError(t, err)
require.NoError(t, err)
assert.EqualValues(t, 245, s.Foo)
}
@ -381,7 +507,7 @@ func TestMappingCustomStructTypeWithFormTag(t *testing.T) {
FileData customUnmarshalParamType `form:"data"`
}
err := mappingByPtr(&s, formSource{"data": {`file:/foo:happiness`}}, "form")
assert.NoError(t, err)
require.NoError(t, err)
assert.EqualValues(t, "file", s.FileData.Protocol)
assert.EqualValues(t, "/foo", s.FileData.Path)
@ -393,7 +519,7 @@ func TestMappingCustomStructTypeWithURITag(t *testing.T) {
FileData customUnmarshalParamType `uri:"data"`
}
err := mappingByPtr(&s, formSource{"data": {`file:/foo:happiness`}}, "uri")
assert.NoError(t, err)
require.NoError(t, err)
assert.EqualValues(t, "file", s.FileData.Protocol)
assert.EqualValues(t, "/foo", s.FileData.Path)
@ -405,7 +531,7 @@ func TestMappingCustomPointerStructTypeWithFormTag(t *testing.T) {
FileData *customUnmarshalParamType `form:"data"`
}
err := mappingByPtr(&s, formSource{"data": {`file:/foo:happiness`}}, "form")
assert.NoError(t, err)
require.NoError(t, err)
assert.EqualValues(t, "file", s.FileData.Protocol)
assert.EqualValues(t, "/foo", s.FileData.Path)
@ -417,7 +543,7 @@ func TestMappingCustomPointerStructTypeWithURITag(t *testing.T) {
FileData *customUnmarshalParamType `uri:"data"`
}
err := mappingByPtr(&s, formSource{"data": {`file:/foo:happiness`}}, "uri")
assert.NoError(t, err)
require.NoError(t, err)
assert.EqualValues(t, "file", s.FileData.Protocol)
assert.EqualValues(t, "/foo", s.FileData.Path)
@ -442,7 +568,7 @@ func TestMappingCustomSliceUri(t *testing.T) {
FileData customPath `uri:"path"`
}
err := mappingByPtr(&s, formSource{"path": {`bar/foo`}}, "uri")
assert.NoError(t, err)
require.NoError(t, err)
assert.EqualValues(t, "bar", s.FileData[0])
assert.EqualValues(t, "foo", s.FileData[1])
@ -453,7 +579,7 @@ func TestMappingCustomSliceForm(t *testing.T) {
FileData customPath `form:"path"`
}
err := mappingByPtr(&s, formSource{"path": {`bar/foo`}}, "form")
assert.NoError(t, err)
require.NoError(t, err)
assert.EqualValues(t, "bar", s.FileData[0])
assert.EqualValues(t, "foo", s.FileData[1])
@ -492,7 +618,7 @@ func TestMappingCustomArrayUri(t *testing.T) {
}
val := `664a062ac74a8ad104e0e80f`
err := mappingByPtr(&s, formSource{"id": {val}}, "uri")
assert.NoError(t, err)
require.NoError(t, err)
expected, _ := convertTo(val)
assert.EqualValues(t, expected, s.FileData)
@ -504,7 +630,7 @@ func TestMappingCustomArrayForm(t *testing.T) {
}
val := `664a062ac74a8ad104e0e80f`
err := mappingByPtr(&s, formSource{"id": {val}}, "form")
assert.NoError(t, err)
require.NoError(t, err)
expected, _ := convertTo(val)
assert.EqualValues(t, expected, s.FileData)

View File

@ -12,6 +12,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestFormMultipartBindingBindOneFile(t *testing.T) {
@ -27,7 +28,7 @@ func TestFormMultipartBindingBindOneFile(t *testing.T) {
req := createRequestMultipartFiles(t, file)
err := FormMultipart.Bind(req, &s)
assert.NoError(t, err)
require.NoError(t, err)
assertMultipartFileHeader(t, &s.FileValue, file)
assertMultipartFileHeader(t, s.FilePtr, file)
@ -53,7 +54,7 @@ func TestFormMultipartBindingBindTwoFiles(t *testing.T) {
req := createRequestMultipartFiles(t, files...)
err := FormMultipart.Bind(req, &s)
assert.NoError(t, err)
require.NoError(t, err)
assert.Len(t, s.SliceValues, len(files))
assert.Len(t, s.SlicePtrs, len(files))
@ -90,7 +91,7 @@ func TestFormMultipartBindingBindError(t *testing.T) {
} {
req := createRequestMultipartFiles(t, files...)
err := FormMultipart.Bind(req, tt.s)
assert.Error(t, err)
require.Error(t, err)
}
}
@ -106,17 +107,17 @@ func createRequestMultipartFiles(t *testing.T, files ...testFile) *http.Request
mw := multipart.NewWriter(&body)
for _, file := range files {
fw, err := mw.CreateFormFile(file.Fieldname, file.Filename)
assert.NoError(t, err)
require.NoError(t, err)
n, err := fw.Write(file.Content)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, len(file.Content), n)
}
err := mw.Close()
assert.NoError(t, err)
require.NoError(t, err)
req, err := http.NewRequest("POST", "/", &body)
assert.NoError(t, err)
require.NoError(t, err)
req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+mw.Boundary())
return req
@ -127,12 +128,12 @@ func assertMultipartFileHeader(t *testing.T, fh *multipart.FileHeader, file test
assert.Equal(t, int64(len(file.Content)), fh.Size)
fl, err := fh.Open()
assert.NoError(t, err)
require.NoError(t, err)
body, err := io.ReadAll(fl)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, string(file.Content), string(body))
err = fl.Close()
assert.NoError(t, err)
require.NoError(t, err)
}

View File

@ -11,6 +11,7 @@ import (
"github.com/go-playground/validator/v10"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type testInterface interface {
@ -113,10 +114,10 @@ func TestValidateNoValidationValues(t *testing.T) {
test := createNoValidationValues()
empty := structNoValidationValues{}
assert.Nil(t, validate(test))
assert.Nil(t, validate(&test))
assert.Nil(t, validate(empty))
assert.Nil(t, validate(&empty))
require.NoError(t, validate(test))
require.NoError(t, validate(&test))
require.NoError(t, validate(empty))
require.NoError(t, validate(&empty))
assert.Equal(t, origin, test)
}
@ -163,8 +164,8 @@ func TestValidateNoValidationPointers(t *testing.T) {
//assert.Nil(t, validate(test))
//assert.Nil(t, validate(&test))
assert.Nil(t, validate(empty))
assert.Nil(t, validate(&empty))
require.NoError(t, validate(empty))
require.NoError(t, validate(&empty))
//assert.Equal(t, origin, test)
}
@ -173,22 +174,22 @@ type Object map[string]any
func TestValidatePrimitives(t *testing.T) {
obj := Object{"foo": "bar", "bar": 1}
assert.NoError(t, validate(obj))
assert.NoError(t, validate(&obj))
require.NoError(t, validate(obj))
require.NoError(t, validate(&obj))
assert.Equal(t, Object{"foo": "bar", "bar": 1}, obj)
obj2 := []Object{{"foo": "bar", "bar": 1}, {"foo": "bar", "bar": 1}}
assert.NoError(t, validate(obj2))
assert.NoError(t, validate(&obj2))
require.NoError(t, validate(obj2))
require.NoError(t, validate(&obj2))
nu := 10
assert.NoError(t, validate(nu))
assert.NoError(t, validate(&nu))
require.NoError(t, validate(nu))
require.NoError(t, validate(&nu))
assert.Equal(t, 10, nu)
str := "value"
assert.NoError(t, validate(str))
assert.NoError(t, validate(&str))
require.NoError(t, validate(str))
require.NoError(t, validate(&str))
assert.Equal(t, "value", str)
}
@ -212,8 +213,8 @@ func TestValidateAndModifyStruct(t *testing.T) {
s := structModifyValidation{Integer: 1}
errs := validate(&s)
assert.Nil(t, errs)
assert.Equal(t, s, structModifyValidation{Integer: 0})
require.NoError(t, errs)
assert.Equal(t, structModifyValidation{Integer: 0}, s)
}
// structCustomValidation is a helper struct we use to check that
@ -239,14 +240,14 @@ func TestValidatorEngine(t *testing.T) {
err := engine.RegisterValidation("notone", notOne)
// Check that we can register custom validation without error
assert.Nil(t, err)
require.NoError(t, err)
// Create an instance which will fail validation
withOne := structCustomValidation{Integer: 1}
errs := validate(withOne)
// Check that we got back non-nil errs
assert.NotNil(t, errs)
require.Error(t, errs)
// Check that the error matches expectation
assert.Error(t, errs, "", "", "notone")
require.Error(t, errs, "", "", "notone")
}

View File

@ -315,7 +315,31 @@ func (c *Context) GetInt(key string) (i int) {
return
}
// GetInt64 returns the value associated with the key as an integer.
// GetInt8 returns the value associated with the key as an integer 8.
func (c *Context) GetInt8(key string) (i8 int8) {
if val, ok := c.Get(key); ok && val != nil {
i8, _ = val.(int8)
}
return
}
// GetInt16 returns the value associated with the key as an integer 16.
func (c *Context) GetInt16(key string) (i16 int16) {
if val, ok := c.Get(key); ok && val != nil {
i16, _ = val.(int16)
}
return
}
// GetInt32 returns the value associated with the key as an integer 32.
func (c *Context) GetInt32(key string) (i32 int32) {
if val, ok := c.Get(key); ok && val != nil {
i32, _ = val.(int32)
}
return
}
// GetInt64 returns the value associated with the key as an integer 64.
func (c *Context) GetInt64(key string) (i64 int64) {
if val, ok := c.Get(key); ok && val != nil {
i64, _ = val.(int64)
@ -331,7 +355,31 @@ func (c *Context) GetUint(key string) (ui uint) {
return
}
// GetUint64 returns the value associated with the key as an unsigned integer.
// GetUint8 returns the value associated with the key as an unsigned integer 8.
func (c *Context) GetUint8(key string) (ui8 uint8) {
if val, ok := c.Get(key); ok && val != nil {
ui8, _ = val.(uint8)
}
return
}
// GetUint16 returns the value associated with the key as an unsigned integer 16.
func (c *Context) GetUint16(key string) (ui16 uint16) {
if val, ok := c.Get(key); ok && val != nil {
ui16, _ = val.(uint16)
}
return
}
// GetUint32 returns the value associated with the key as an unsigned integer 32.
func (c *Context) GetUint32(key string) (ui32 uint32) {
if val, ok := c.Get(key); ok && val != nil {
ui32, _ = val.(uint32)
}
return
}
// GetUint64 returns the value associated with the key as an unsigned integer 64.
func (c *Context) GetUint64(key string) (ui64 uint64) {
if val, ok := c.Get(key); ok && val != nil {
ui64, _ = val.(uint64)
@ -339,6 +387,14 @@ func (c *Context) GetUint64(key string) (ui64 uint64) {
return
}
// GetFloat32 returns the value associated with the key as a float32.
func (c *Context) GetFloat32(key string) (f32 float32) {
if val, ok := c.Get(key); ok && val != nil {
f32, _ = val.(float32)
}
return
}
// GetFloat64 returns the value associated with the key as a float64.
func (c *Context) GetFloat64(key string) (f64 float64) {
if val, ok := c.Get(key); ok && val != nil {
@ -363,6 +419,90 @@ func (c *Context) GetDuration(key string) (d time.Duration) {
return
}
func (c *Context) GetIntSlice(key string) (is []int) {
if val, ok := c.Get(key); ok && val != nil {
is, _ = val.([]int)
}
return
}
func (c *Context) GetInt8Slice(key string) (i8s []int8) {
if val, ok := c.Get(key); ok && val != nil {
i8s, _ = val.([]int8)
}
return
}
func (c *Context) GetInt16Slice(key string) (i16s []int16) {
if val, ok := c.Get(key); ok && val != nil {
i16s, _ = val.([]int16)
}
return
}
func (c *Context) GetInt32Slice(key string) (i32s []int32) {
if val, ok := c.Get(key); ok && val != nil {
i32s, _ = val.([]int32)
}
return
}
func (c *Context) GetInt64Slice(key string) (i64s []int64) {
if val, ok := c.Get(key); ok && val != nil {
i64s, _ = val.([]int64)
}
return
}
func (c *Context) GetUintSlice(key string) (uis []uint) {
if val, ok := c.Get(key); ok && val != nil {
uis, _ = val.([]uint)
}
return
}
func (c *Context) GetUint8Slice(key string) (ui8s []uint8) {
if val, ok := c.Get(key); ok && val != nil {
ui8s, _ = val.([]uint8)
}
return
}
func (c *Context) GetUint16Slice(key string) (ui16s []uint16) {
if val, ok := c.Get(key); ok && val != nil {
ui16s, _ = val.([]uint16)
}
return
}
func (c *Context) GetUint32Slice(key string) (ui32s []uint32) {
if val, ok := c.Get(key); ok && val != nil {
ui32s, _ = val.([]uint32)
}
return
}
func (c *Context) GetUint64Slice(key string) (ui64s []uint64) {
if val, ok := c.Get(key); ok && val != nil {
ui64s, _ = val.([]uint64)
}
return
}
func (c *Context) GetFloat32Slice(key string) (f32s []float32) {
if val, ok := c.Get(key); ok && val != nil {
f32s, _ = val.([]float32)
}
return
}
func (c *Context) GetFloat64Slice(key string) (f64s []float64) {
if val, ok := c.Get(key); ok && val != nil {
f64s, _ = val.([]float64)
}
return
}
// GetStringSlice returns the value associated with the key as a slice of strings.
func (c *Context) GetStringSlice(key string) (ss []string) {
if val, ok := c.Get(key); ok && val != nil {

View File

@ -27,6 +27,7 @@ import (
"github.com/gin-gonic/gin/binding"
testdata "github.com/gin-gonic/gin/testdata/protoexample"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
)
@ -74,20 +75,18 @@ func TestContextFormFile(t *testing.T) {
buf := new(bytes.Buffer)
mw := multipart.NewWriter(buf)
w, err := mw.CreateFormFile("file", "test")
if assert.NoError(t, err) {
_, err = w.Write([]byte("test"))
assert.NoError(t, err)
}
require.NoError(t, err)
_, err = w.Write([]byte("test"))
require.NoError(t, err)
mw.Close()
c, _ := CreateTestContext(httptest.NewRecorder())
c.Request, _ = http.NewRequest("POST", "/", buf)
c.Request.Header.Set("Content-Type", mw.FormDataContentType())
f, err := c.FormFile("file")
if assert.NoError(t, err) {
assert.Equal(t, "test", f.Filename)
}
require.NoError(t, err)
assert.Equal(t, "test", f.Filename)
assert.NoError(t, c.SaveUploadedFile(f, "test"))
require.NoError(t, c.SaveUploadedFile(f, "test"))
}
func TestContextFormFileFailed(t *testing.T) {
@ -99,29 +98,27 @@ func TestContextFormFileFailed(t *testing.T) {
c.Request.Header.Set("Content-Type", mw.FormDataContentType())
c.engine.MaxMultipartMemory = 8 << 20
f, err := c.FormFile("file")
assert.Error(t, err)
require.Error(t, err)
assert.Nil(t, f)
}
func TestContextMultipartForm(t *testing.T) {
buf := new(bytes.Buffer)
mw := multipart.NewWriter(buf)
assert.NoError(t, mw.WriteField("foo", "bar"))
require.NoError(t, mw.WriteField("foo", "bar"))
w, err := mw.CreateFormFile("file", "test")
if assert.NoError(t, err) {
_, err = w.Write([]byte("test"))
assert.NoError(t, err)
}
require.NoError(t, err)
_, err = w.Write([]byte("test"))
require.NoError(t, err)
mw.Close()
c, _ := CreateTestContext(httptest.NewRecorder())
c.Request, _ = http.NewRequest("POST", "/", buf)
c.Request.Header.Set("Content-Type", mw.FormDataContentType())
f, err := c.MultipartForm()
if assert.NoError(t, err) {
assert.NotNil(t, f)
}
require.NoError(t, err)
assert.NotNil(t, f)
assert.NoError(t, c.SaveUploadedFile(f.File["file"][0], "test"))
require.NoError(t, c.SaveUploadedFile(f.File["file"][0], "test"))
}
func TestSaveUploadedOpenFailed(t *testing.T) {
@ -136,27 +133,25 @@ func TestSaveUploadedOpenFailed(t *testing.T) {
f := &multipart.FileHeader{
Filename: "file",
}
assert.Error(t, c.SaveUploadedFile(f, "test"))
require.Error(t, c.SaveUploadedFile(f, "test"))
}
func TestSaveUploadedCreateFailed(t *testing.T) {
buf := new(bytes.Buffer)
mw := multipart.NewWriter(buf)
w, err := mw.CreateFormFile("file", "test")
if assert.NoError(t, err) {
_, err = w.Write([]byte("test"))
assert.NoError(t, err)
}
require.NoError(t, err)
_, err = w.Write([]byte("test"))
require.NoError(t, err)
mw.Close()
c, _ := CreateTestContext(httptest.NewRecorder())
c.Request, _ = http.NewRequest("POST", "/", buf)
c.Request.Header.Set("Content-Type", mw.FormDataContentType())
f, err := c.FormFile("file")
if assert.NoError(t, err) {
assert.Equal(t, "test", f.Filename)
}
require.NoError(t, err)
assert.Equal(t, "test", f.Filename)
assert.Error(t, c.SaveUploadedFile(f, "/"))
require.Error(t, c.SaveUploadedFile(f, "/"))
}
func TestContextReset(t *testing.T) {
@ -174,10 +169,10 @@ func TestContextReset(t *testing.T) {
assert.False(t, c.IsAborted())
assert.Nil(t, c.Keys)
assert.Nil(t, c.Accepted)
assert.Len(t, c.Errors, 0)
assert.Empty(t, c.Errors)
assert.Empty(t, c.Errors.Errors())
assert.Empty(t, c.Errors.ByType(ErrorTypeAny))
assert.Len(t, c.Params, 0)
assert.Empty(t, c.Params)
assert.EqualValues(t, c.index, -1)
assert.Equal(t, c.Writer.(*responseWriter), &c.writermem)
}
@ -230,13 +225,13 @@ func TestContextSetGetValues(t *testing.T) {
var a any = 1
c.Set("intInterface", a)
assert.Exactly(t, c.MustGet("string").(string), "this is a string")
assert.Exactly(t, "this is a string", c.MustGet("string").(string))
assert.Exactly(t, c.MustGet("int32").(int32), int32(-42))
assert.Exactly(t, c.MustGet("int64").(int64), int64(42424242424242))
assert.Exactly(t, c.MustGet("uint64").(uint64), uint64(42))
assert.Exactly(t, c.MustGet("float32").(float32), float32(4.2))
assert.Exactly(t, c.MustGet("float64").(float64), 4.2)
assert.Exactly(t, c.MustGet("intInterface").(int), 1)
assert.Exactly(t, int64(42424242424242), c.MustGet("int64").(int64))
assert.Exactly(t, uint64(42), c.MustGet("uint64").(uint64))
assert.InDelta(t, float32(4.2), c.MustGet("float32").(float32), 0.01)
assert.InDelta(t, 4.2, c.MustGet("float64").(float64), 0.01)
assert.Exactly(t, 1, c.MustGet("intInterface").(int))
}
func TestContextGetString(t *testing.T) {
@ -257,6 +252,30 @@ func TestContextGetInt(t *testing.T) {
assert.Equal(t, 1, c.GetInt("int"))
}
func TestContextGetInt8(t *testing.T) {
c, _ := CreateTestContext(httptest.NewRecorder())
key := "int8"
value := int8(0x7F)
c.Set(key, value)
assert.Equal(t, value, c.GetInt8(key))
}
func TestContextGetInt16(t *testing.T) {
c, _ := CreateTestContext(httptest.NewRecorder())
key := "int16"
value := int16(0x7FFF)
c.Set(key, value)
assert.Equal(t, value, c.GetInt16(key))
}
func TestContextGetInt32(t *testing.T) {
c, _ := CreateTestContext(httptest.NewRecorder())
key := "int32"
value := int32(0x7FFFFFFF)
c.Set(key, value)
assert.Equal(t, value, c.GetInt32(key))
}
func TestContextGetInt64(t *testing.T) {
c, _ := CreateTestContext(httptest.NewRecorder())
c.Set("int64", int64(42424242424242))
@ -269,16 +288,48 @@ func TestContextGetUint(t *testing.T) {
assert.Equal(t, uint(1), c.GetUint("uint"))
}
func TestContextGetUint8(t *testing.T) {
c, _ := CreateTestContext(httptest.NewRecorder())
key := "uint8"
value := uint8(0xFF)
c.Set(key, value)
assert.Equal(t, value, c.GetUint8(key))
}
func TestContextGetUint16(t *testing.T) {
c, _ := CreateTestContext(httptest.NewRecorder())
key := "uint16"
value := uint16(0xFFFF)
c.Set(key, value)
assert.Equal(t, value, c.GetUint16(key))
}
func TestContextGetUint32(t *testing.T) {
c, _ := CreateTestContext(httptest.NewRecorder())
key := "uint32"
value := uint32(0xFFFFFFFF)
c.Set(key, value)
assert.Equal(t, value, c.GetUint32(key))
}
func TestContextGetUint64(t *testing.T) {
c, _ := CreateTestContext(httptest.NewRecorder())
c.Set("uint64", uint64(18446744073709551615))
assert.Equal(t, uint64(18446744073709551615), c.GetUint64("uint64"))
}
func TestContextGetFloat32(t *testing.T) {
c, _ := CreateTestContext(httptest.NewRecorder())
key := "float32"
value := float32(3.14)
c.Set(key, value)
assert.Equal(t, value, c.GetFloat32(key))
}
func TestContextGetFloat64(t *testing.T) {
c, _ := CreateTestContext(httptest.NewRecorder())
c.Set("float64", 4.2)
assert.Equal(t, 4.2, c.GetFloat64("float64"))
assert.InDelta(t, 4.2, c.GetFloat64("float64"), 0.01)
}
func TestContextGetTime(t *testing.T) {
@ -294,6 +345,102 @@ func TestContextGetDuration(t *testing.T) {
assert.Equal(t, time.Second, c.GetDuration("duration"))
}
func TestContextGetIntSlice(t *testing.T) {
c, _ := CreateTestContext(httptest.NewRecorder())
key := "int-slice"
value := []int{1, 2}
c.Set(key, value)
assert.Equal(t, value, c.GetIntSlice(key))
}
func TestContextGetInt8Slice(t *testing.T) {
c, _ := CreateTestContext(httptest.NewRecorder())
key := "int8-slice"
value := []int8{1, 2}
c.Set(key, value)
assert.Equal(t, value, c.GetInt8Slice(key))
}
func TestContextGetInt16Slice(t *testing.T) {
c, _ := CreateTestContext(httptest.NewRecorder())
key := "int16-slice"
value := []int16{1, 2}
c.Set(key, value)
assert.Equal(t, value, c.GetInt16Slice(key))
}
func TestContextGetInt32Slice(t *testing.T) {
c, _ := CreateTestContext(httptest.NewRecorder())
key := "int32-slice"
value := []int32{1, 2}
c.Set(key, value)
assert.Equal(t, value, c.GetInt32Slice(key))
}
func TestContextGetInt64Slice(t *testing.T) {
c, _ := CreateTestContext(httptest.NewRecorder())
key := "int64-slice"
value := []int64{1, 2}
c.Set(key, value)
assert.Equal(t, value, c.GetInt64Slice(key))
}
func TestContextGetUintSlice(t *testing.T) {
c, _ := CreateTestContext(httptest.NewRecorder())
key := "uint-slice"
value := []uint{1, 2}
c.Set(key, value)
assert.Equal(t, value, c.GetUintSlice(key))
}
func TestContextGetUint8Slice(t *testing.T) {
c, _ := CreateTestContext(httptest.NewRecorder())
key := "uint8-slice"
value := []uint8{1, 2}
c.Set(key, value)
assert.Equal(t, value, c.GetUint8Slice(key))
}
func TestContextGetUint16Slice(t *testing.T) {
c, _ := CreateTestContext(httptest.NewRecorder())
key := "uint16-slice"
value := []uint16{1, 2}
c.Set(key, value)
assert.Equal(t, value, c.GetUint16Slice(key))
}
func TestContextGetUint32Slice(t *testing.T) {
c, _ := CreateTestContext(httptest.NewRecorder())
key := "uint32-slice"
value := []uint32{1, 2}
c.Set(key, value)
assert.Equal(t, value, c.GetUint32Slice(key))
}
func TestContextGetUint64Slice(t *testing.T) {
c, _ := CreateTestContext(httptest.NewRecorder())
key := "uint64-slice"
value := []uint64{1, 2}
c.Set(key, value)
assert.Equal(t, value, c.GetUint64Slice(key))
}
func TestContextGetFloat32Slice(t *testing.T) {
c, _ := CreateTestContext(httptest.NewRecorder())
key := "float32-slice"
value := []float32{1, 2}
c.Set(key, value)
assert.Equal(t, value, c.GetFloat32Slice(key))
}
func TestContextGetFloat64Slice(t *testing.T) {
c, _ := CreateTestContext(httptest.NewRecorder())
key := "float64-slice"
value := []float64{1, 2}
c.Set(key, value)
assert.Equal(t, value, c.GetFloat64Slice(key))
}
func TestContextGetStringSlice(t *testing.T) {
c, _ := CreateTestContext(httptest.NewRecorder())
c.Set("slice", []string{"foo"})
@ -344,12 +491,12 @@ func TestContextCopy(t *testing.T) {
assert.Nil(t, cp.writermem.ResponseWriter)
assert.Equal(t, &cp.writermem, cp.Writer.(*responseWriter))
assert.Equal(t, cp.Request, c.Request)
assert.Equal(t, cp.index, abortIndex)
assert.Equal(t, abortIndex, cp.index)
assert.Equal(t, cp.Keys, c.Keys)
assert.Equal(t, cp.engine, c.engine)
assert.Equal(t, cp.Params, c.Params)
cp.Set("foo", "notBar")
assert.False(t, cp.Keys["foo"] == c.Keys["foo"])
assert.NotEqual(t, cp.Keys["foo"], c.Keys["foo"])
assert.Equal(t, cp.fullPath, c.fullPath)
}
@ -366,7 +513,7 @@ func TestContextHandlerNames(t *testing.T) {
names := c.HandlerNames()
assert.True(t, len(names) == 4)
assert.Len(t, names, 4)
for _, name := range names {
assert.Regexp(t, `^(.*/vendor/)?(github\.com/gin-gonic/gin\.){1}(TestContextHandlerNames\.func.*){0,1}(handlerNameTest.*){0,1}`, name)
}
@ -425,7 +572,7 @@ func TestContextQuery(t *testing.T) {
func TestContextInitQueryCache(t *testing.T) {
validURL, err := url.Parse("https://github.com/gin-gonic/gin/pull/3969?key=value&otherkey=othervalue")
assert.Nil(t, err)
require.NoError(t, err)
tests := []struct {
testName string
@ -531,7 +678,7 @@ func TestContextQueryAndPostForm(t *testing.T) {
Both string `form:"both"`
Array []string `form:"array[]"`
}
assert.NoError(t, c.Bind(&obj))
require.NoError(t, c.Bind(&obj))
assert.Equal(t, "bar", obj.Foo, "bar")
assert.Equal(t, "main", obj.ID, "main")
assert.Equal(t, 11, obj.Page, 11)
@ -548,10 +695,10 @@ func TestContextQueryAndPostForm(t *testing.T) {
assert.Equal(t, "second", values[1])
values = c.QueryArray("nokey")
assert.Equal(t, 0, len(values))
assert.Empty(t, values)
values = c.QueryArray("both")
assert.Equal(t, 1, len(values))
assert.Len(t, values, 1)
assert.Equal(t, "GET", values[0])
dicts, ok := c.GetQueryMap("ids")
@ -561,22 +708,22 @@ func TestContextQueryAndPostForm(t *testing.T) {
dicts, ok = c.GetQueryMap("nokey")
assert.False(t, ok)
assert.Equal(t, 0, len(dicts))
assert.Empty(t, dicts)
dicts, ok = c.GetQueryMap("both")
assert.False(t, ok)
assert.Equal(t, 0, len(dicts))
assert.Empty(t, dicts)
dicts, ok = c.GetQueryMap("array")
assert.False(t, ok)
assert.Equal(t, 0, len(dicts))
assert.Empty(t, dicts)
dicts = c.QueryMap("ids")
assert.Equal(t, "hi", dicts["a"])
assert.Equal(t, "3.14", dicts["b"])
dicts = c.QueryMap("nokey")
assert.Equal(t, 0, len(dicts))
assert.Empty(t, dicts)
}
func TestContextPostFormMultipart(t *testing.T) {
@ -594,7 +741,7 @@ func TestContextPostFormMultipart(t *testing.T) {
TimeLocation time.Time `form:"time_location" time_format:"02/01/2006 15:04" time_location:"Asia/Tokyo"`
BlankTime time.Time `form:"blank_time" time_format:"02/01/2006 15:04"`
}
assert.NoError(t, c.Bind(&obj))
require.NoError(t, c.Bind(&obj))
assert.Equal(t, "bar", obj.Foo)
assert.Equal(t, "10", obj.Bar)
assert.Equal(t, 10, obj.BarAsInt)
@ -648,10 +795,10 @@ func TestContextPostFormMultipart(t *testing.T) {
assert.Equal(t, "second", values[1])
values = c.PostFormArray("nokey")
assert.Equal(t, 0, len(values))
assert.Empty(t, values)
values = c.PostFormArray("foo")
assert.Equal(t, 1, len(values))
assert.Len(t, values, 1)
assert.Equal(t, "bar", values[0])
dicts, ok := c.GetPostFormMap("names")
@ -661,14 +808,14 @@ func TestContextPostFormMultipart(t *testing.T) {
dicts, ok = c.GetPostFormMap("nokey")
assert.False(t, ok)
assert.Equal(t, 0, len(dicts))
assert.Empty(t, dicts)
dicts = c.PostFormMap("names")
assert.Equal(t, "thinkerou", dicts["a"])
assert.Equal(t, "tianou", dicts["b"])
dicts = c.PostFormMap("nokey")
assert.Equal(t, 0, len(dicts))
assert.Empty(t, dicts)
}
func TestContextSetCookie(t *testing.T) {
@ -693,7 +840,7 @@ func TestContextGetCookie(t *testing.T) {
assert.Equal(t, "gin", cookie)
_, err := c.Cookie("nokey")
assert.Error(t, err)
require.Error(t, err)
}
func TestContextBodyAllowedForStatus(t *testing.T) {
@ -798,7 +945,7 @@ func TestContextRenderNoContentAPIJSON(t *testing.T) {
assert.Equal(t, http.StatusNoContent, w.Code)
assert.Empty(t, w.Body.String())
assert.Equal(t, w.Header().Get("Content-Type"), "application/vnd.api+json")
assert.Equal(t, "application/vnd.api+json", w.Header().Get("Content-Type"))
}
// Tests that the response is serialized as JSON
@ -1160,7 +1307,7 @@ func TestContextRenderProtoBuf(t *testing.T) {
c.ProtoBuf(http.StatusCreated, data)
protoData, err := proto.Marshal(data)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, http.StatusCreated, w.Code)
assert.Equal(t, string(protoData), w.Body.String())
@ -1321,7 +1468,7 @@ func TestContextNegotiationNotSupport(t *testing.T) {
})
assert.Equal(t, http.StatusNotAcceptable, w.Code)
assert.Equal(t, c.index, abortIndex)
assert.Equal(t, abortIndex, c.index)
assert.True(t, c.IsAborted())
}
@ -1349,23 +1496,23 @@ func TestContextNegotiationFormatWithWildcardAccept(t *testing.T) {
c.Request, _ = http.NewRequest("POST", "/", nil)
c.Request.Header.Add("Accept", "*/*")
assert.Equal(t, c.NegotiateFormat("*/*"), "*/*")
assert.Equal(t, c.NegotiateFormat("text/*"), "text/*")
assert.Equal(t, c.NegotiateFormat("application/*"), "application/*")
assert.Equal(t, c.NegotiateFormat(MIMEJSON), MIMEJSON)
assert.Equal(t, c.NegotiateFormat(MIMEXML), MIMEXML)
assert.Equal(t, c.NegotiateFormat(MIMEHTML), MIMEHTML)
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, MIMEXML, c.NegotiateFormat(MIMEXML))
assert.Equal(t, MIMEHTML, c.NegotiateFormat(MIMEHTML))
c, _ = CreateTestContext(httptest.NewRecorder())
c.Request, _ = http.NewRequest("POST", "/", nil)
c.Request.Header.Add("Accept", "text/*")
assert.Equal(t, c.NegotiateFormat("*/*"), "*/*")
assert.Equal(t, c.NegotiateFormat("text/*"), "text/*")
assert.Equal(t, c.NegotiateFormat("application/*"), "")
assert.Equal(t, c.NegotiateFormat(MIMEJSON), "")
assert.Equal(t, c.NegotiateFormat(MIMEXML), "")
assert.Equal(t, c.NegotiateFormat(MIMEHTML), MIMEHTML)
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.Equal(t, MIMEHTML, c.NegotiateFormat(MIMEHTML))
}
func TestContextNegotiationFormatCustom(t *testing.T) {
@ -1444,7 +1591,7 @@ func TestContextAbortWithStatusJSON(t *testing.T) {
buf := new(bytes.Buffer)
_, err := buf.ReadFrom(w.Body)
assert.NoError(t, err)
require.NoError(t, err)
jsonStringBody := buf.String()
assert.Equal(t, "{\"foo\":\"fooValue\",\"bar\":\"barValue\"}", jsonStringBody)
}
@ -1669,7 +1816,7 @@ func TestContextAutoBindJSON(t *testing.T) {
Foo string `json:"foo"`
Bar string `json:"bar"`
}
assert.NoError(t, c.Bind(&obj))
require.NoError(t, c.Bind(&obj))
assert.Equal(t, "foo", obj.Bar)
assert.Equal(t, "bar", obj.Foo)
assert.Empty(t, c.Errors)
@ -1686,7 +1833,7 @@ func TestContextBindWithJSON(t *testing.T) {
Foo string `json:"foo"`
Bar string `json:"bar"`
}
assert.NoError(t, c.BindJSON(&obj))
require.NoError(t, c.BindJSON(&obj))
assert.Equal(t, "foo", obj.Bar)
assert.Equal(t, "bar", obj.Foo)
assert.Equal(t, 0, w.Body.Len())
@ -1707,7 +1854,7 @@ func TestContextBindWithXML(t *testing.T) {
Foo string `xml:"foo"`
Bar string `xml:"bar"`
}
assert.NoError(t, c.BindXML(&obj))
require.NoError(t, c.BindXML(&obj))
assert.Equal(t, "FOO", obj.Foo)
assert.Equal(t, "BAR", obj.Bar)
assert.Equal(t, 0, w.Body.Len())
@ -1722,7 +1869,7 @@ func TestContextBindPlain(t *testing.T) {
var s string
assert.NoError(t, c.BindPlain(&s))
require.NoError(t, c.BindPlain(&s))
assert.Equal(t, "test string", s)
assert.Equal(t, 0, w.Body.Len())
@ -1732,7 +1879,7 @@ func TestContextBindPlain(t *testing.T) {
var bs []byte
assert.NoError(t, c.BindPlain(&bs))
require.NoError(t, c.BindPlain(&bs))
assert.Equal(t, []byte("test []byte"), bs)
assert.Equal(t, 0, w.Body.Len())
}
@ -1752,7 +1899,7 @@ func TestContextBindHeader(t *testing.T) {
Limit int `header:"limit"`
}
assert.NoError(t, c.BindHeader(&testHeader))
require.NoError(t, c.BindHeader(&testHeader))
assert.Equal(t, 8000, testHeader.Rate)
assert.Equal(t, "music", testHeader.Domain)
assert.Equal(t, 1000, testHeader.Limit)
@ -1769,7 +1916,7 @@ func TestContextBindWithQuery(t *testing.T) {
Foo string `form:"foo"`
Bar string `form:"bar"`
}
assert.NoError(t, c.BindQuery(&obj))
require.NoError(t, c.BindQuery(&obj))
assert.Equal(t, "foo", obj.Bar)
assert.Equal(t, "bar", obj.Foo)
assert.Equal(t, 0, w.Body.Len())
@ -1786,7 +1933,7 @@ func TestContextBindWithYAML(t *testing.T) {
Foo string `yaml:"foo"`
Bar string `yaml:"bar"`
}
assert.NoError(t, c.BindYAML(&obj))
require.NoError(t, c.BindYAML(&obj))
assert.Equal(t, "foo", obj.Bar)
assert.Equal(t, "bar", obj.Foo)
assert.Equal(t, 0, w.Body.Len())
@ -1803,7 +1950,7 @@ func TestContextBindWithTOML(t *testing.T) {
Foo string `toml:"foo"`
Bar string `toml:"bar"`
}
assert.NoError(t, c.BindTOML(&obj))
require.NoError(t, c.BindTOML(&obj))
assert.Equal(t, "foo", obj.Bar)
assert.Equal(t, "bar", obj.Foo)
assert.Equal(t, 0, w.Body.Len())
@ -1821,7 +1968,7 @@ func TestContextBadAutoBind(t *testing.T) {
}
assert.False(t, c.IsAborted())
assert.Error(t, c.Bind(&obj))
require.Error(t, c.Bind(&obj))
c.Writer.WriteHeaderNow()
assert.Empty(t, obj.Bar)
@ -1839,7 +1986,7 @@ func TestContextAutoShouldBindJSON(t *testing.T) {
Foo string `json:"foo"`
Bar string `json:"bar"`
}
assert.NoError(t, c.ShouldBind(&obj))
require.NoError(t, c.ShouldBind(&obj))
assert.Equal(t, "foo", obj.Bar)
assert.Equal(t, "bar", obj.Foo)
assert.Empty(t, c.Errors)
@ -1856,7 +2003,7 @@ func TestContextShouldBindWithJSON(t *testing.T) {
Foo string `json:"foo"`
Bar string `json:"bar"`
}
assert.NoError(t, c.ShouldBindJSON(&obj))
require.NoError(t, c.ShouldBindJSON(&obj))
assert.Equal(t, "foo", obj.Bar)
assert.Equal(t, "bar", obj.Foo)
assert.Equal(t, 0, w.Body.Len())
@ -1877,7 +2024,7 @@ func TestContextShouldBindWithXML(t *testing.T) {
Foo string `xml:"foo"`
Bar string `xml:"bar"`
}
assert.NoError(t, c.ShouldBindXML(&obj))
require.NoError(t, c.ShouldBindXML(&obj))
assert.Equal(t, "FOO", obj.Foo)
assert.Equal(t, "BAR", obj.Bar)
assert.Equal(t, 0, w.Body.Len())
@ -1892,7 +2039,7 @@ func TestContextShouldBindPlain(t *testing.T) {
var s string
assert.NoError(t, c.ShouldBindPlain(&s))
require.NoError(t, c.ShouldBindPlain(&s))
assert.Equal(t, "test string", s)
assert.Equal(t, 0, w.Body.Len())
// []byte
@ -1902,7 +2049,7 @@ func TestContextShouldBindPlain(t *testing.T) {
var bs []byte
assert.NoError(t, c.ShouldBindPlain(&bs))
require.NoError(t, c.ShouldBindPlain(&bs))
assert.Equal(t, []byte("test []byte"), bs)
assert.Equal(t, 0, w.Body.Len())
}
@ -1922,7 +2069,7 @@ func TestContextShouldBindHeader(t *testing.T) {
Limit int `header:"limit"`
}
assert.NoError(t, c.ShouldBindHeader(&testHeader))
require.NoError(t, c.ShouldBindHeader(&testHeader))
assert.Equal(t, 8000, testHeader.Rate)
assert.Equal(t, "music", testHeader.Domain)
assert.Equal(t, 1000, testHeader.Limit)
@ -1941,7 +2088,7 @@ func TestContextShouldBindWithQuery(t *testing.T) {
Foo1 string `form:"Foo"`
Bar1 string `form:"Bar"`
}
assert.NoError(t, c.ShouldBindQuery(&obj))
require.NoError(t, c.ShouldBindQuery(&obj))
assert.Equal(t, "foo", obj.Bar)
assert.Equal(t, "bar", obj.Foo)
assert.Equal(t, "foo1", obj.Bar1)
@ -1960,7 +2107,7 @@ func TestContextShouldBindWithYAML(t *testing.T) {
Foo string `yaml:"foo"`
Bar string `yaml:"bar"`
}
assert.NoError(t, c.ShouldBindYAML(&obj))
require.NoError(t, c.ShouldBindYAML(&obj))
assert.Equal(t, "foo", obj.Bar)
assert.Equal(t, "bar", obj.Foo)
assert.Equal(t, 0, w.Body.Len())
@ -1977,7 +2124,7 @@ func TestContextShouldBindWithTOML(t *testing.T) {
Foo string `toml:"foo"`
Bar string `toml:"bar"`
}
assert.NoError(t, c.ShouldBindTOML(&obj))
require.NoError(t, c.ShouldBindTOML(&obj))
assert.Equal(t, "foo", obj.Bar)
assert.Equal(t, "bar", obj.Foo)
assert.Equal(t, 0, w.Body.Len())
@ -1995,7 +2142,7 @@ func TestContextBadAutoShouldBind(t *testing.T) {
}
assert.False(t, c.IsAborted())
assert.Error(t, c.ShouldBind(&obj))
require.Error(t, c.ShouldBind(&obj))
assert.Empty(t, obj.Bar)
assert.Empty(t, obj.Foo)
@ -2056,10 +2203,10 @@ func TestContextShouldBindBodyWith(t *testing.T) {
// When it binds to typeA and typeB, it finds the body is
// not typeB but typeA.
objA := typeA{}
assert.NoError(t, c.ShouldBindBodyWith(&objA, tt.bindingA))
require.NoError(t, c.ShouldBindBodyWith(&objA, tt.bindingA))
assert.Equal(t, typeA{"FOO"}, objA)
objB := typeB{}
assert.Error(t, c.ShouldBindBodyWith(&objB, tt.bindingB))
require.Error(t, c.ShouldBindBodyWith(&objB, tt.bindingB))
assert.NotEqual(t, typeB{"BAR"}, objB)
}
// bodyB to typeA and typeB
@ -2072,10 +2219,10 @@ func TestContextShouldBindBodyWith(t *testing.T) {
"POST", "http://example.com", bytes.NewBufferString(tt.bodyB),
)
objA := typeA{}
assert.Error(t, c.ShouldBindBodyWith(&objA, tt.bindingA))
require.Error(t, c.ShouldBindBodyWith(&objA, tt.bindingA))
assert.NotEqual(t, typeA{"FOO"}, objA)
objB := typeB{}
assert.NoError(t, c.ShouldBindBodyWith(&objB, tt.bindingB))
require.NoError(t, c.ShouldBindBodyWith(&objB, tt.bindingB))
assert.Equal(t, typeB{"BAR"}, objB)
}
}
@ -2124,22 +2271,22 @@ func TestContextShouldBindBodyWithJSON(t *testing.T) {
objJSON := typeJSON{}
if tt.bindingBody == binding.JSON {
assert.NoError(t, c.ShouldBindBodyWithJSON(&objJSON))
require.NoError(t, c.ShouldBindBodyWithJSON(&objJSON))
assert.Equal(t, typeJSON{"FOO"}, objJSON)
}
if tt.bindingBody == binding.XML {
assert.Error(t, c.ShouldBindBodyWithJSON(&objJSON))
require.Error(t, c.ShouldBindBodyWithJSON(&objJSON))
assert.Equal(t, typeJSON{}, objJSON)
}
if tt.bindingBody == binding.YAML {
assert.Error(t, c.ShouldBindBodyWithJSON(&objJSON))
require.Error(t, c.ShouldBindBodyWithJSON(&objJSON))
assert.Equal(t, typeJSON{}, objJSON)
}
if tt.bindingBody == binding.TOML {
assert.Error(t, c.ShouldBindBodyWithJSON(&objJSON))
require.Error(t, c.ShouldBindBodyWithJSON(&objJSON))
assert.Equal(t, typeJSON{}, objJSON)
}
}
@ -2188,22 +2335,22 @@ func TestContextShouldBindBodyWithXML(t *testing.T) {
objXML := typeXML{}
if tt.bindingBody == binding.JSON {
assert.Error(t, c.ShouldBindBodyWithXML(&objXML))
require.Error(t, c.ShouldBindBodyWithXML(&objXML))
assert.Equal(t, typeXML{}, objXML)
}
if tt.bindingBody == binding.XML {
assert.NoError(t, c.ShouldBindBodyWithXML(&objXML))
require.NoError(t, c.ShouldBindBodyWithXML(&objXML))
assert.Equal(t, typeXML{"FOO"}, objXML)
}
if tt.bindingBody == binding.YAML {
assert.Error(t, c.ShouldBindBodyWithXML(&objXML))
require.Error(t, c.ShouldBindBodyWithXML(&objXML))
assert.Equal(t, typeXML{}, objXML)
}
if tt.bindingBody == binding.TOML {
assert.Error(t, c.ShouldBindBodyWithXML(&objXML))
require.Error(t, c.ShouldBindBodyWithXML(&objXML))
assert.Equal(t, typeXML{}, objXML)
}
}
@ -2253,22 +2400,22 @@ func TestContextShouldBindBodyWithYAML(t *testing.T) {
// YAML belongs to a super collection of JSON, so JSON can be parsed by YAML
if tt.bindingBody == binding.JSON {
assert.NoError(t, c.ShouldBindBodyWithYAML(&objYAML))
require.NoError(t, c.ShouldBindBodyWithYAML(&objYAML))
assert.Equal(t, typeYAML{"FOO"}, objYAML)
}
if tt.bindingBody == binding.XML {
assert.Error(t, c.ShouldBindBodyWithYAML(&objYAML))
require.Error(t, c.ShouldBindBodyWithYAML(&objYAML))
assert.Equal(t, typeYAML{}, objYAML)
}
if tt.bindingBody == binding.YAML {
assert.NoError(t, c.ShouldBindBodyWithYAML(&objYAML))
require.NoError(t, c.ShouldBindBodyWithYAML(&objYAML))
assert.Equal(t, typeYAML{"FOO"}, objYAML)
}
if tt.bindingBody == binding.TOML {
assert.Error(t, c.ShouldBindBodyWithYAML(&objYAML))
require.Error(t, c.ShouldBindBodyWithYAML(&objYAML))
assert.Equal(t, typeYAML{}, objYAML)
}
}
@ -2317,22 +2464,22 @@ func TestContextShouldBindBodyWithTOML(t *testing.T) {
objTOML := typeTOML{}
if tt.bindingBody == binding.JSON {
assert.Error(t, c.ShouldBindBodyWithTOML(&objTOML))
require.Error(t, c.ShouldBindBodyWithTOML(&objTOML))
assert.Equal(t, typeTOML{}, objTOML)
}
if tt.bindingBody == binding.XML {
assert.Error(t, c.ShouldBindBodyWithTOML(&objTOML))
require.Error(t, c.ShouldBindBodyWithTOML(&objTOML))
assert.Equal(t, typeTOML{}, objTOML)
}
if tt.bindingBody == binding.YAML {
assert.Error(t, c.ShouldBindBodyWithTOML(&objTOML))
require.Error(t, c.ShouldBindBodyWithTOML(&objTOML))
assert.Equal(t, typeTOML{}, objTOML)
}
if tt.bindingBody == binding.TOML {
assert.NoError(t, c.ShouldBindBodyWithTOML(&objTOML))
require.NoError(t, c.ShouldBindBodyWithTOML(&objTOML))
assert.Equal(t, typeTOML{"FOO"}, objTOML)
}
}
@ -2387,27 +2534,27 @@ func TestContextShouldBindBodyWithPlain(t *testing.T) {
if tt.bindingBody == binding.Plain {
body := ""
assert.NoError(t, c.ShouldBindBodyWithPlain(&body))
assert.Equal(t, body, "foo=FOO")
require.NoError(t, c.ShouldBindBodyWithPlain(&body))
assert.Equal(t, "foo=FOO", body)
}
if tt.bindingBody == binding.JSON {
assert.NoError(t, c.ShouldBindBodyWithJSON(&objJSON))
require.NoError(t, c.ShouldBindBodyWithJSON(&objJSON))
assert.Equal(t, typeJSON{"FOO"}, objJSON)
}
if tt.bindingBody == binding.XML {
assert.Error(t, c.ShouldBindBodyWithJSON(&objJSON))
require.Error(t, c.ShouldBindBodyWithJSON(&objJSON))
assert.Equal(t, typeJSON{}, objJSON)
}
if tt.bindingBody == binding.YAML {
assert.Error(t, c.ShouldBindBodyWithJSON(&objJSON))
require.Error(t, c.ShouldBindBodyWithJSON(&objJSON))
assert.Equal(t, typeJSON{}, objJSON)
}
if tt.bindingBody == binding.TOML {
assert.Error(t, c.ShouldBindBodyWithJSON(&objJSON))
require.Error(t, c.ShouldBindBodyWithJSON(&objJSON))
assert.Equal(t, typeJSON{}, objJSON)
}
}
@ -2416,10 +2563,10 @@ func TestContextShouldBindBodyWithPlain(t *testing.T) {
func TestContextGolangContext(t *testing.T) {
c, _ := CreateTestContext(httptest.NewRecorder())
c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString("{\"foo\":\"bar\", \"bar\":\"foo\"}"))
assert.NoError(t, c.Err())
require.NoError(t, c.Err())
assert.Nil(t, c.Done())
ti, ok := c.Deadline()
assert.Equal(t, ti, time.Time{})
assert.Equal(t, time.Time{}, ti)
assert.False(t, ok)
assert.Equal(t, c.Value(ContextRequestKey), c.Request)
assert.Equal(t, c.Value(ContextKey), c)
@ -2468,7 +2615,7 @@ func TestContextGetRawData(t *testing.T) {
c.Request.Header.Add("Content-Type", MIMEPOSTForm)
data, err := c.GetRawData()
assert.Nil(t, err)
require.NoError(t, err)
assert.Equal(t, "Fetch binary post data", string(data))
}
@ -2539,7 +2686,7 @@ func TestContextStream(t *testing.T) {
}()
_, err := w.Write([]byte("test"))
assert.NoError(t, err)
require.NoError(t, err)
return stopStream
})
@ -2557,7 +2704,7 @@ func TestContextStreamWithClientGone(t *testing.T) {
}()
_, err := writer.Write([]byte("test"))
assert.NoError(t, err)
require.NoError(t, err)
return true
})
@ -2685,7 +2832,7 @@ func TestContextWithFallbackErrFromRequestContext(t *testing.T) {
// enable ContextWithFallback feature flag
c.engine.ContextWithFallback = true
assert.Nil(t, c.Err())
require.NoError(t, c.Err())
c2, _ := CreateTestContext(httptest.NewRecorder())
// enable ContextWithFallback feature flag
@ -2834,7 +2981,7 @@ func TestContextAddParam(t *testing.T) {
c.AddParam(id, value)
v, ok := c.Params.Get(id)
assert.Equal(t, ok, true)
assert.True(t, ok)
assert.Equal(t, value, v)
}

View File

@ -17,6 +17,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// TODO
@ -154,13 +155,13 @@ func TestGetMinVer(t *testing.T) {
var m uint64
var e error
_, e = getMinVer("go1")
assert.NotNil(t, e)
require.Error(t, e)
m, e = getMinVer("go1.1")
assert.Equal(t, uint64(1), m)
assert.Nil(t, e)
require.NoError(t, e)
m, e = getMinVer("go1.1.1")
assert.Nil(t, e)
require.NoError(t, e)
assert.Equal(t, uint64(1), m)
_, e = getMinVer("go1.1.1.1")
assert.NotNil(t, e)
require.Error(t, e)
}

View File

@ -26,6 +26,8 @@
- [Custom Validators](#custom-validators)
- [Only Bind Query String](#only-bind-query-string)
- [Bind Query String or Post Data](#bind-query-string-or-post-data)
- [Bind default value if none provided](#bind-default-value-if-none-provided)
- [Collection format for arrays](#collection-format-for-arrays)
- [Bind Uri](#bind-uri)
- [Bind custom unmarshaler](#bind-custom-unmarshaler)
- [Bind Header](#bind-header)
@ -338,16 +340,16 @@ func main() {
router := gin.Default()
// Simple group: v1
v1 := router.Group("/v1")
{
v1 := router.Group("/v1")
v1.POST("/login", loginEndpoint)
v1.POST("/submit", submitEndpoint)
v1.POST("/read", readEndpoint)
}
// Simple group: v2
v2 := router.Group("/v2")
{
v2 := router.Group("/v2")
v2.POST("/login", loginEndpoint)
v2.POST("/submit", submitEndpoint)
v2.POST("/read", readEndpoint)
@ -524,7 +526,7 @@ func main() {
return c.Writer.Status() < http.StatusInternalServerError
}
engine.Use(gin.LoggerWithConfig(loggerConfig))
router.Use(gin.LoggerWithConfig(loggerConfig))
router.Use(gin.Recovery())
// skipped
@ -861,6 +863,106 @@ Test it with:
curl -X GET "localhost:8085/testing?name=appleboy&address=xyz&birthday=1992-03-15&createTime=1562400033000000123&unixTime=1562400033"
```
### Bind default value if none provided
If the server should bind a default value to a field when the client does not provide one, specify the default value using the `default` key within the `form` tag:
```
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
type Person struct {
Name string `form:"name,default=William"`
Age int `form:"age,default=10"`
Friends []string `form:"friends,default=Will;Bill"`
Addresses [2]string `form:"addresses,default=foo bar" collection_format:"ssv"`
LapTimes []int `form:"lap_times,default=1;2;3" collection_format:"csv"`
}
func main() {
g := gin.Default()
g.POST("/person", func(c *gin.Context) {
var req Person
if err := c.ShouldBindQuery(&req); err != nil {
c.JSON(http.StatusBadRequest, err)
return
}
c.JSON(http.StatusOK, req)
})
_ = g.Run("localhost:8080")
}
```
```
curl -X POST http://localhost:8080/person
{"Name":"William","Age":10,"Friends":["Will","Bill"],"Colors":["red","blue"],"LapTimes":[1,2,3]}
```
NOTE: For default [collection values](#collection-format-for-arrays), the following rules apply:
- Since commas are used to delimit tag options, they are not supported within a default value and will result in undefined behavior
- For the collection formats "multi" and "csv", a semicolon should be used in place of a comma to delimited default values
- Since semicolons are used to delimit default values for "multi" and "csv", they are not supported within a default value for "multi" and "csv"
#### Collection format for arrays
| Format | Description | Example |
| --------------- | --------------------------------------------------------- | ----------------------- |
| multi (default) | Multiple parameter instances rather than multiple values. | key=foo&key=bar&key=baz |
| csv | Comma-separated values. | foo,bar,baz |
| ssv | Space-separated values. | foo bar baz |
| tsv | Tab-separated values. | "foo\tbar\tbaz" |
| pipes | Pipe-separated values. | foo\|bar\|baz |
```go
package main
import (
"log"
"time"
"github.com/gin-gonic/gin"
)
type Person struct {
Name string `form:"name"`
Addresses []string `form:"addresses" collection_format:"csv"`
Birthday time.Time `form:"birthday" time_format:"2006-01-02" time_utc:"1"`
CreateTime time.Time `form:"createTime" time_format:"unixNano"`
UnixTime time.Time `form:"unixTime" time_format:"unix"`
}
func main() {
route := gin.Default()
route.GET("/testing", startPage)
route.Run(":8085")
}
func startPage(c *gin.Context) {
var person Person
// If `GET`, only `Form` binding engine (`query`) used.
// If `POST`, first checks the `content-type` for `JSON` or `XML`, then uses `Form` (`form-data`).
// See more at https://github.com/gin-gonic/gin/blob/master/binding/binding.go#L48
if c.ShouldBind(&person) == nil {
log.Println(person.Name)
log.Println(person.Addresses)
log.Println(person.Birthday)
log.Println(person.CreateTime)
log.Println(person.UnixTime)
}
c.String(200, "Success")
}
```
Test it with:
```sh
$ curl -X GET "localhost:8085/testing?name=appleboy&addresses=foo,bar&birthday=1992-03-15&createTime=1562400033000000123&unixTime=1562400033"
```
### Bind Uri
See the [detail information](https://github.com/gin-gonic/gin/issues/846).

View File

@ -11,6 +11,7 @@ import (
"github.com/gin-gonic/gin/internal/json"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestError(t *testing.T) {
@ -122,7 +123,7 @@ func TestErrorUnwrap(t *testing.T) {
})
// check that 'errors.Is()' and 'errors.As()' behave as expected :
assert.True(t, errors.Is(err, innerErr))
require.ErrorIs(t, err, innerErr)
var testErr TestErr
assert.True(t, errors.As(err, &testErr))
require.ErrorAs(t, err, &testErr)
}

View File

@ -7,6 +7,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type mockFileSystem struct {
@ -28,7 +29,7 @@ func TestOnlyFilesFS_Open(t *testing.T) {
file, err := fs.Open("foo")
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, testFile, file.(neutralizedReaddirFile).File)
}
@ -43,7 +44,7 @@ func TestOnlyFilesFS_Open_err(t *testing.T) {
file, err := fs.Open("foo")
assert.ErrorIs(t, err, testError)
require.ErrorIs(t, err, testError)
assert.Nil(t, file)
}
@ -52,7 +53,7 @@ func Test_neuteredReaddirFile_Readdir(t *testing.T) {
res, err := n.Readdir(0)
assert.NoError(t, err)
require.NoError(t, err)
assert.Nil(t, res)
}

2
gin.go
View File

@ -687,7 +687,7 @@ func (engine *Engine) handleHTTPRequest(c *Context) {
break
}
if engine.HandleMethodNotAllowed {
if engine.HandleMethodNotAllowed && len(t) > 0 {
// According to RFC 7231 section 6.5.5, MUST generate an Allow header field in response
// containing a list of the target resource's currently supported methods.
allowed := make([]string, 0, len(t)-1)

View File

@ -21,6 +21,7 @@ import (
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// params[0]=url example:http://127.0.0.1:8080/index (cannot be empty)
@ -40,11 +41,11 @@ func testRequest(t *testing.T, params ...string) {
client := &http.Client{Transport: tr}
resp, err := client.Get(params[0])
assert.NoError(t, err)
require.NoError(t, err)
defer resp.Body.Close()
body, ioerr := io.ReadAll(resp.Body)
assert.NoError(t, ioerr)
require.NoError(t, ioerr)
var responseStatus = "200 OK"
if len(params) > 1 && params[1] != "" {
@ -73,13 +74,13 @@ func TestRunEmpty(t *testing.T) {
// otherwise the main thread will complete
time.Sleep(5 * time.Millisecond)
assert.Error(t, router.Run(":8080"))
require.Error(t, router.Run(":8080"))
testRequest(t, "http://localhost:8080/example")
}
func TestBadTrustedCIDRs(t *testing.T) {
router := New()
assert.Error(t, router.SetTrustedProxies([]string{"hello/world"}))
require.Error(t, router.SetTrustedProxies([]string{"hello/world"}))
}
/* legacy tests
@ -87,7 +88,7 @@ func TestBadTrustedCIDRsForRun(t *testing.T) {
os.Setenv("PORT", "")
router := New()
router.TrustedProxies = []string{"hello/world"}
assert.Error(t, router.Run(":8080"))
require.Error(t, router.Run(":8080"))
}
func TestBadTrustedCIDRsForRunUnix(t *testing.T) {
@ -100,7 +101,7 @@ func TestBadTrustedCIDRsForRunUnix(t *testing.T) {
go func() {
router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })
assert.Error(t, router.RunUnix(unixTestSocket))
require.Error(t, router.RunUnix(unixTestSocket))
}()
// have to wait for the goroutine to start and run the server
// otherwise the main thread will complete
@ -112,15 +113,15 @@ func TestBadTrustedCIDRsForRunFd(t *testing.T) {
router.TrustedProxies = []string{"hello/world"}
addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
assert.NoError(t, err)
require.NoError(t, err)
listener, err := net.ListenTCP("tcp", addr)
assert.NoError(t, err)
require.NoError(t, err)
socketFile, err := listener.File()
assert.NoError(t, err)
require.NoError(t, err)
go func() {
router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })
assert.Error(t, router.RunFd(int(socketFile.Fd())))
require.Error(t, router.RunFd(int(socketFile.Fd())))
}()
// have to wait for the goroutine to start and run the server
// otherwise the main thread will complete
@ -132,12 +133,12 @@ func TestBadTrustedCIDRsForRunListener(t *testing.T) {
router.TrustedProxies = []string{"hello/world"}
addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
assert.NoError(t, err)
require.NoError(t, err)
listener, err := net.ListenTCP("tcp", addr)
assert.NoError(t, err)
require.NoError(t, err)
go func() {
router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })
assert.Error(t, router.RunListener(listener))
require.Error(t, router.RunListener(listener))
}()
// have to wait for the goroutine to start and run the server
// otherwise the main thread will complete
@ -148,7 +149,7 @@ func TestBadTrustedCIDRsForRunTLS(t *testing.T) {
os.Setenv("PORT", "")
router := New()
router.TrustedProxies = []string{"hello/world"}
assert.Error(t, router.RunTLS(":8080", "./testdata/certificate/cert.pem", "./testdata/certificate/key.pem"))
require.Error(t, router.RunTLS(":8080", "./testdata/certificate/cert.pem", "./testdata/certificate/key.pem"))
}
*/
@ -164,7 +165,7 @@ func TestRunTLS(t *testing.T) {
// otherwise the main thread will complete
time.Sleep(5 * time.Millisecond)
assert.Error(t, router.RunTLS(":8443", "./testdata/certificate/cert.pem", "./testdata/certificate/key.pem"))
require.Error(t, router.RunTLS(":8443", "./testdata/certificate/cert.pem", "./testdata/certificate/key.pem"))
testRequest(t, "https://localhost:8443/example")
}
@ -201,7 +202,7 @@ func TestPusher(t *testing.T) {
// otherwise the main thread will complete
time.Sleep(5 * time.Millisecond)
assert.Error(t, router.RunTLS(":8449", "./testdata/certificate/cert.pem", "./testdata/certificate/key.pem"))
require.Error(t, router.RunTLS(":8449", "./testdata/certificate/cert.pem", "./testdata/certificate/key.pem"))
testRequest(t, "https://localhost:8449/pusher")
}
@ -216,14 +217,14 @@ func TestRunEmptyWithEnv(t *testing.T) {
// otherwise the main thread will complete
time.Sleep(5 * time.Millisecond)
assert.Error(t, router.Run(":3123"))
require.Error(t, router.Run(":3123"))
testRequest(t, "http://localhost:3123/example")
}
func TestRunTooMuchParams(t *testing.T) {
router := New()
assert.Panics(t, func() {
assert.NoError(t, router.Run("2", "2"))
require.NoError(t, router.Run("2", "2"))
})
}
@ -237,7 +238,7 @@ func TestRunWithPort(t *testing.T) {
// otherwise the main thread will complete
time.Sleep(5 * time.Millisecond)
assert.Error(t, router.Run(":5150"))
require.Error(t, router.Run(":5150"))
testRequest(t, "http://localhost:5150/example")
}
@ -257,7 +258,7 @@ func TestUnixSocket(t *testing.T) {
time.Sleep(5 * time.Millisecond)
c, err := net.Dial("unix", unixTestSocket)
assert.NoError(t, err)
require.NoError(t, err)
fmt.Fprint(c, "GET /example HTTP/1.0\r\n\r\n")
scanner := bufio.NewScanner(c)
@ -271,7 +272,7 @@ func TestUnixSocket(t *testing.T) {
func TestBadUnixSocket(t *testing.T) {
router := New()
assert.Error(t, router.RunUnix("#/tmp/unix_unit_test"))
require.Error(t, router.RunUnix("#/tmp/unix_unit_test"))
}
func TestRunQUIC(t *testing.T) {
@ -286,7 +287,7 @@ func TestRunQUIC(t *testing.T) {
// otherwise the main thread will complete
time.Sleep(5 * time.Millisecond)
assert.Error(t, router.RunQUIC(":8443", "./testdata/certificate/cert.pem", "./testdata/certificate/key.pem"))
require.Error(t, router.RunQUIC(":8443", "./testdata/certificate/cert.pem", "./testdata/certificate/key.pem"))
testRequest(t, "https://localhost:8443/example")
}
@ -294,15 +295,15 @@ func TestFileDescriptor(t *testing.T) {
router := New()
addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
assert.NoError(t, err)
require.NoError(t, err)
listener, err := net.ListenTCP("tcp", addr)
assert.NoError(t, err)
require.NoError(t, err)
socketFile, err := listener.File()
if isWindows() {
// not supported by windows, it is unimplemented now
assert.Error(t, err)
require.Error(t, err)
} else {
assert.NoError(t, err)
require.NoError(t, err)
}
if socketFile == nil {
@ -318,7 +319,7 @@ func TestFileDescriptor(t *testing.T) {
time.Sleep(5 * time.Millisecond)
c, err := net.Dial("tcp", listener.Addr().String())
assert.NoError(t, err)
require.NoError(t, err)
fmt.Fprintf(c, "GET /example HTTP/1.0\r\n\r\n")
scanner := bufio.NewScanner(c)
@ -332,15 +333,15 @@ func TestFileDescriptor(t *testing.T) {
func TestBadFileDescriptor(t *testing.T) {
router := New()
assert.Error(t, router.RunFd(0))
require.Error(t, router.RunFd(0))
}
func TestListener(t *testing.T) {
router := New()
addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
assert.NoError(t, err)
require.NoError(t, err)
listener, err := net.ListenTCP("tcp", addr)
assert.NoError(t, err)
require.NoError(t, err)
go func() {
router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })
assert.NoError(t, router.RunListener(listener))
@ -350,7 +351,7 @@ func TestListener(t *testing.T) {
time.Sleep(5 * time.Millisecond)
c, err := net.Dial("tcp", listener.Addr().String())
assert.NoError(t, err)
require.NoError(t, err)
fmt.Fprintf(c, "GET /example HTTP/1.0\r\n\r\n")
scanner := bufio.NewScanner(c)
@ -365,11 +366,11 @@ func TestListener(t *testing.T) {
func TestBadListener(t *testing.T) {
router := New()
addr, err := net.ResolveTCPAddr("tcp", "localhost:10086")
assert.NoError(t, err)
require.NoError(t, err)
listener, err := net.ListenTCP("tcp", addr)
assert.NoError(t, err)
require.NoError(t, err)
listener.Close()
assert.Error(t, router.RunListener(listener))
require.Error(t, router.RunListener(listener))
}
func TestWithHttptestWithAutoSelectedPort(t *testing.T) {
@ -395,7 +396,14 @@ func TestConcurrentHandleContext(t *testing.T) {
wg.Add(iterations)
for i := 0; i < iterations; i++ {
go func() {
testGetRequestHandler(t, router, "/")
req, err := http.NewRequest(http.MethodGet, "/", nil)
assert.NoError(t, err)
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
assert.Equal(t, "it worked", w.Body.String(), "resp body should match")
assert.Equal(t, 200, w.Code, "should get a 200")
wg.Done()
}()
}
@ -417,17 +425,6 @@ func TestConcurrentHandleContext(t *testing.T) {
// testRequest(t, "http://localhost:8033/example")
// }
func testGetRequestHandler(t *testing.T, h http.Handler, url string) {
req, err := http.NewRequest(http.MethodGet, url, nil)
assert.NoError(t, err)
w := httptest.NewRecorder()
h.ServeHTTP(w, req)
assert.Equal(t, "it worked", w.Body.String(), "resp body should match")
assert.Equal(t, 200, w.Code, "should get a 200")
}
func TestTreeRunDynamicRouting(t *testing.T) {
router := New()
router.GET("/aa/*xx", func(c *Context) { c.String(http.StatusOK, "/aa/*xx") })

View File

@ -20,6 +20,7 @@ import (
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/net/http2"
)
@ -547,10 +548,10 @@ func TestEngineHandleContextManyReEntries(t *testing.T) {
r.GET("/:count", func(c *Context) {
countStr := c.Param("count")
count, err := strconv.Atoi(countStr)
assert.NoError(t, err)
require.NoError(t, err)
n, err := c.Writer.Write([]byte("."))
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, 1, n)
switch {
@ -580,7 +581,7 @@ func TestPrepareTrustedCIRDsWith(t *testing.T) {
expectedTrustedCIDRs := []*net.IPNet{parseCIDR("0.0.0.0/0")}
err := r.SetTrustedProxies([]string{"0.0.0.0/0"})
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, expectedTrustedCIDRs, r.trustedCIDRs)
}
@ -588,7 +589,7 @@ func TestPrepareTrustedCIRDsWith(t *testing.T) {
{
err := r.SetTrustedProxies([]string{"192.168.1.33/33"})
assert.Error(t, err)
require.Error(t, err)
}
// valid ipv4 address
@ -597,7 +598,7 @@ func TestPrepareTrustedCIRDsWith(t *testing.T) {
err := r.SetTrustedProxies([]string{"192.168.1.33"})
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, expectedTrustedCIDRs, r.trustedCIDRs)
}
@ -605,7 +606,7 @@ func TestPrepareTrustedCIRDsWith(t *testing.T) {
{
err := r.SetTrustedProxies([]string{"192.168.1.256"})
assert.Error(t, err)
require.Error(t, err)
}
// valid ipv6 address
@ -613,7 +614,7 @@ func TestPrepareTrustedCIRDsWith(t *testing.T) {
expectedTrustedCIDRs := []*net.IPNet{parseCIDR("2002:0000:0000:1234:abcd:ffff:c0a8:0101/128")}
err := r.SetTrustedProxies([]string{"2002:0000:0000:1234:abcd:ffff:c0a8:0101"})
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, expectedTrustedCIDRs, r.trustedCIDRs)
}
@ -621,7 +622,7 @@ func TestPrepareTrustedCIRDsWith(t *testing.T) {
{
err := r.SetTrustedProxies([]string{"gggg:0000:0000:1234:abcd:ffff:c0a8:0101"})
assert.Error(t, err)
require.Error(t, err)
}
// valid ipv6 cidr
@ -629,7 +630,7 @@ func TestPrepareTrustedCIRDsWith(t *testing.T) {
expectedTrustedCIDRs := []*net.IPNet{parseCIDR("::/0")}
err := r.SetTrustedProxies([]string{"::/0"})
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, expectedTrustedCIDRs, r.trustedCIDRs)
}
@ -637,7 +638,7 @@ func TestPrepareTrustedCIRDsWith(t *testing.T) {
{
err := r.SetTrustedProxies([]string{"gggg:0000:0000:1234:abcd:ffff:c0a8:0101/129"})
assert.Error(t, err)
require.Error(t, err)
}
// valid combination
@ -653,7 +654,7 @@ func TestPrepareTrustedCIRDsWith(t *testing.T) {
"172.16.0.1",
})
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, expectedTrustedCIDRs, r.trustedCIDRs)
}
@ -665,7 +666,7 @@ func TestPrepareTrustedCIRDsWith(t *testing.T) {
"172.16.0.256",
})
assert.Error(t, err)
require.Error(t, err)
}
// nil value
@ -673,7 +674,7 @@ func TestPrepareTrustedCIRDsWith(t *testing.T) {
err := r.SetTrustedProxies(nil)
assert.Nil(t, r.trustedCIDRs)
assert.Nil(t, err)
require.NoError(t, err)
}
}
@ -754,3 +755,14 @@ func TestCustomUnmarshalStruct(t *testing.T) {
assert.Equal(t, 200, w.Code)
assert.Equal(t, `"2000/01/01"`, w.Body.String())
}
// Test the fix for https://github.com/gin-gonic/gin/issues/4002
func TestMethodNotAllowedNoRoute(t *testing.T) {
g := New()
g.HandleMethodNotAllowed = true
req := httptest.NewRequest("GET", "/", nil)
resp := httptest.NewRecorder()
assert.NotPanics(t, func() { g.ServeHTTP(resp, req) })
assert.Equal(t, http.StatusNotFound, resp.Code)
}

View File

@ -14,6 +14,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type route struct {
@ -295,9 +296,9 @@ func TestShouldBindUri(t *testing.T) {
}
router.Handle(http.MethodGet, "/rest/:name/:id", func(c *Context) {
var person Person
assert.NoError(t, c.ShouldBindUri(&person))
assert.True(t, person.Name != "")
assert.True(t, person.ID != "")
require.NoError(t, c.ShouldBindUri(&person))
assert.NotEqual(t, "", person.Name)
assert.NotEqual(t, "", person.ID)
c.String(http.StatusOK, "ShouldBindUri test OK")
})
@ -317,9 +318,9 @@ func TestBindUri(t *testing.T) {
}
router.Handle(http.MethodGet, "/rest/:name/:id", func(c *Context) {
var person Person
assert.NoError(t, c.BindUri(&person))
assert.True(t, person.Name != "")
assert.True(t, person.ID != "")
require.NoError(t, c.BindUri(&person))
assert.NotEqual(t, "", person.Name)
assert.NotEqual(t, "", person.ID)
c.String(http.StatusOK, "BindUri test OK")
})
@ -338,7 +339,7 @@ func TestBindUriError(t *testing.T) {
}
router.Handle(http.MethodGet, "/new/rest/:num", func(c *Context) {
var m Member
assert.Error(t, c.BindUri(&m))
require.Error(t, c.BindUri(&m))
})
path1, _ := exampleFromPath("/new/rest/:num")

14
go.mod
View File

@ -11,9 +11,10 @@ require (
github.com/mattn/go-isatty v0.0.20
github.com/pelletier/go-toml/v2 v2.2.2
github.com/quic-go/quic-go v0.43.1
github.com/spf13/cast v1.7.0
github.com/stretchr/testify v1.9.0
github.com/ugorji/go/codec v1.2.12
golang.org/x/net v0.25.0
golang.org/x/net v0.27.0
google.golang.org/protobuf v1.34.1
gopkg.in/yaml.v3 v3.0.1
)
@ -29,7 +30,6 @@ require (
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
@ -39,10 +39,10 @@ require (
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
go.uber.org/mock v0.4.0 // indirect
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/crypto v0.25.0 // indirect
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect
golang.org/x/mod v0.11.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect
golang.org/x/tools v0.9.1 // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/sys v0.22.0 // indirect
golang.org/x/text v0.16.0 // indirect
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
)

36
go.sum
View File

@ -9,10 +9,11 @@ github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
@ -33,8 +34,8 @@ github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
@ -62,7 +63,6 @@ github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
@ -71,6 +71,8 @@ github.com/quic-go/quic-go v0.43.1 h1:fLiMNfQVe9q2JvSsiXo4fXOEguXHGGl9+6gLp4RPeZ
github.com/quic-go/quic-go v0.43.1/go.mod h1:132kz4kL3F9vxhW3CtQJLDVwcFe5wdWeJXXijhsO57M=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
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=
@ -92,24 +94,26 @@ go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
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.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db h1:D/cFflL63o2KSLJIwjlcIt8PR064j/xsmdEJL/YvY/o=
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
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.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo=
golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View File

@ -329,13 +329,13 @@ func TestIsOutputColor(t *testing.T) {
}
consoleColorMode = autoColor
assert.Equal(t, true, p.IsOutputColor())
assert.True(t, p.IsOutputColor())
ForceConsoleColor()
assert.Equal(t, true, p.IsOutputColor())
assert.True(t, p.IsOutputColor())
DisableConsoleColor()
assert.Equal(t, false, p.IsOutputColor())
assert.False(t, p.IsOutputColor())
// test with isTerm flag false.
p = LogFormatterParams{
@ -343,13 +343,13 @@ func TestIsOutputColor(t *testing.T) {
}
consoleColorMode = autoColor
assert.Equal(t, false, p.IsOutputColor())
assert.False(t, p.IsOutputColor())
ForceConsoleColor()
assert.Equal(t, true, p.IsOutputColor())
assert.True(t, p.IsOutputColor())
DisableConsoleColor()
assert.Equal(t, false, p.IsOutputColor())
assert.False(t, p.IsOutputColor())
// reset console color mode.
consoleColorMode = autoColor

View File

@ -87,7 +87,7 @@ func TestPathCleanMallocs(t *testing.T) {
for _, test := range cleanTests {
allocs := testing.AllocsPerRun(100, func() { cleanPath(test.result) })
assert.EqualValues(t, allocs, 0)
assert.InDelta(t, 0, allocs, 0.01)
}
}

View File

@ -12,6 +12,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/ugorji/go/codec"
)
@ -29,7 +30,7 @@ func TestRenderMsgPack(t *testing.T) {
err := (MsgPack{data}).Render(w)
assert.NoError(t, err)
require.NoError(t, err)
h := new(codec.MsgpackHandle)
assert.NotNil(t, h)
@ -37,7 +38,7 @@ func TestRenderMsgPack(t *testing.T) {
assert.NotNil(t, buf)
err = codec.NewEncoder(buf, h).Encode(data)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, w.Body.String(), buf.String())
assert.Equal(t, "application/msgpack; charset=utf-8", w.Header().Get("Content-Type"))
}

View File

@ -18,6 +18,7 @@ import (
"github.com/gin-gonic/gin/internal/json"
testdata "github.com/gin-gonic/gin/testdata/protoexample"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
)
@ -36,7 +37,7 @@ func TestRenderJSON(t *testing.T) {
err := (JSON{data}).Render(w)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, "{\"foo\":\"bar\",\"html\":\"\\u003cb\\u003e\"}", w.Body.String())
assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type"))
}
@ -46,7 +47,7 @@ func TestRenderJSONError(t *testing.T) {
data := make(chan int)
// json: unsupported type: chan int
assert.Error(t, (JSON{data}).Render(w))
require.Error(t, (JSON{data}).Render(w))
}
func TestRenderIndentedJSON(t *testing.T) {
@ -58,7 +59,7 @@ func TestRenderIndentedJSON(t *testing.T) {
err := (IndentedJSON{data}).Render(w)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, "{\n \"bar\": \"foo\",\n \"foo\": \"bar\"\n}", w.Body.String())
assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type"))
}
@ -69,7 +70,7 @@ func TestRenderIndentedJSONPanics(t *testing.T) {
// json: unsupported type: chan int
err := (IndentedJSON{data}).Render(w)
assert.Error(t, err)
require.Error(t, err)
}
func TestRenderSecureJSON(t *testing.T) {
@ -83,7 +84,7 @@ func TestRenderSecureJSON(t *testing.T) {
err1 := (SecureJSON{"while(1);", data}).Render(w1)
assert.NoError(t, err1)
require.NoError(t, err1)
assert.Equal(t, "{\"foo\":\"bar\"}", w1.Body.String())
assert.Equal(t, "application/json; charset=utf-8", w1.Header().Get("Content-Type"))
@ -95,7 +96,7 @@ func TestRenderSecureJSON(t *testing.T) {
}}
err2 := (SecureJSON{"while(1);", datas}).Render(w2)
assert.NoError(t, err2)
require.NoError(t, err2)
assert.Equal(t, "while(1);[{\"foo\":\"bar\"},{\"bar\":\"foo\"}]", w2.Body.String())
assert.Equal(t, "application/json; charset=utf-8", w2.Header().Get("Content-Type"))
}
@ -106,7 +107,7 @@ func TestRenderSecureJSONFail(t *testing.T) {
// json: unsupported type: chan int
err := (SecureJSON{"while(1);", data}).Render(w)
assert.Error(t, err)
require.Error(t, err)
}
func TestRenderJsonpJSON(t *testing.T) {
@ -120,7 +121,7 @@ func TestRenderJsonpJSON(t *testing.T) {
err1 := (JsonpJSON{"x", data}).Render(w1)
assert.NoError(t, err1)
require.NoError(t, err1)
assert.Equal(t, "x({\"foo\":\"bar\"});", w1.Body.String())
assert.Equal(t, "application/javascript; charset=utf-8", w1.Header().Get("Content-Type"))
@ -132,7 +133,7 @@ func TestRenderJsonpJSON(t *testing.T) {
}}
err2 := (JsonpJSON{"x", datas}).Render(w2)
assert.NoError(t, err2)
require.NoError(t, err2)
assert.Equal(t, "x([{\"foo\":\"bar\"},{\"bar\":\"foo\"}]);", w2.Body.String())
assert.Equal(t, "application/javascript; charset=utf-8", w2.Header().Get("Content-Type"))
}
@ -191,7 +192,7 @@ func TestRenderJsonpJSONError2(t *testing.T) {
assert.Equal(t, "application/javascript; charset=utf-8", w.Header().Get("Content-Type"))
e := (JsonpJSON{"", data}).Render(w)
assert.NoError(t, e)
require.NoError(t, e)
assert.Equal(t, "{\"foo\":\"bar\"}", w.Body.String())
assert.Equal(t, "application/javascript; charset=utf-8", w.Header().Get("Content-Type"))
@ -203,7 +204,7 @@ func TestRenderJsonpJSONFail(t *testing.T) {
// json: unsupported type: chan int
err := (JsonpJSON{"x", data}).Render(w)
assert.Error(t, err)
require.Error(t, err)
}
func TestRenderAsciiJSON(t *testing.T) {
@ -215,7 +216,7 @@ func TestRenderAsciiJSON(t *testing.T) {
err := (AsciiJSON{data1}).Render(w1)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, "{\"lang\":\"GO\\u8bed\\u8a00\",\"tag\":\"\\u003cbr\\u003e\"}", w1.Body.String())
assert.Equal(t, "application/json", w1.Header().Get("Content-Type"))
@ -223,7 +224,7 @@ func TestRenderAsciiJSON(t *testing.T) {
data2 := 3.1415926
err = (AsciiJSON{data2}).Render(w2)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, "3.1415926", w2.Body.String())
}
@ -232,7 +233,7 @@ func TestRenderAsciiJSONFail(t *testing.T) {
data := make(chan int)
// json: unsupported type: chan int
assert.Error(t, (AsciiJSON{data}).Render(w))
require.Error(t, (AsciiJSON{data}).Render(w))
}
func TestRenderPureJSON(t *testing.T) {
@ -242,7 +243,7 @@ func TestRenderPureJSON(t *testing.T) {
"html": "<b>",
}
err := (PureJSON{data}).Render(w)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, "{\"foo\":\"bar\",\"html\":\"<b>\"}\n", w.Body.String())
assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type"))
}
@ -283,7 +284,7 @@ b:
assert.Equal(t, "application/yaml; charset=utf-8", w.Header().Get("Content-Type"))
err := (YAML{data}).Render(w)
assert.NoError(t, err)
require.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/yaml; charset=utf-8", w.Header().Get("Content-Type"))
}
@ -298,7 +299,7 @@ func (ft *fail) MarshalYAML() (any, error) {
func TestRenderYAMLFail(t *testing.T) {
w := httptest.NewRecorder()
err := (YAML{&fail{}}).Render(w)
assert.Error(t, err)
require.Error(t, err)
}
func TestRenderTOML(t *testing.T) {
@ -311,7 +312,7 @@ func TestRenderTOML(t *testing.T) {
assert.Equal(t, "application/toml; charset=utf-8", w.Header().Get("Content-Type"))
err := (TOML{data}).Render(w)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, "foo = 'bar'\nhtml = '<b>'\n", w.Body.String())
assert.Equal(t, "application/toml; charset=utf-8", w.Header().Get("Content-Type"))
}
@ -319,7 +320,7 @@ func TestRenderTOML(t *testing.T) {
func TestRenderTOMLFail(t *testing.T) {
w := httptest.NewRecorder()
err := (TOML{net.IPv4bcast}).Render(w)
assert.Error(t, err)
require.Error(t, err)
}
// test Protobuf rendering
@ -334,12 +335,12 @@ func TestRenderProtoBuf(t *testing.T) {
(ProtoBuf{data}).WriteContentType(w)
protoData, err := proto.Marshal(data)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, "application/x-protobuf", w.Header().Get("Content-Type"))
err = (ProtoBuf{data}).Render(w)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, string(protoData), w.Body.String())
assert.Equal(t, "application/x-protobuf", w.Header().Get("Content-Type"))
}
@ -348,7 +349,7 @@ func TestRenderProtoBufFail(t *testing.T) {
w := httptest.NewRecorder()
data := &testdata.Test{}
err := (ProtoBuf{data}).Render(w)
assert.Error(t, err)
require.Error(t, err)
}
func TestRenderXML(t *testing.T) {
@ -362,14 +363,14 @@ func TestRenderXML(t *testing.T) {
err := (XML{data}).Render(w)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, "<map><foo>bar</foo></map>", w.Body.String())
assert.Equal(t, "application/xml; charset=utf-8", w.Header().Get("Content-Type"))
}
func TestRenderRedirect(t *testing.T) {
req, err := http.NewRequest("GET", "/test-redirect", nil)
assert.NoError(t, err)
require.NoError(t, err)
data1 := Redirect{
Code: http.StatusMovedPermanently,
@ -379,7 +380,7 @@ func TestRenderRedirect(t *testing.T) {
w := httptest.NewRecorder()
err = data1.Render(w)
assert.NoError(t, err)
require.NoError(t, err)
data2 := Redirect{
Code: http.StatusOK,
@ -390,7 +391,7 @@ func TestRenderRedirect(t *testing.T) {
w = httptest.NewRecorder()
assert.PanicsWithValue(t, "Cannot redirect with status code 200", func() {
err := data2.Render(w)
assert.NoError(t, err)
require.NoError(t, err)
})
data3 := Redirect{
@ -401,7 +402,7 @@ func TestRenderRedirect(t *testing.T) {
w = httptest.NewRecorder()
err = data3.Render(w)
assert.NoError(t, err)
require.NoError(t, err)
// only improve coverage
data2.WriteContentType(w)
@ -416,7 +417,7 @@ func TestRenderData(t *testing.T) {
Data: data,
}).Render(w)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, "#!PNG some raw data", w.Body.String())
assert.Equal(t, "image/png", w.Header().Get("Content-Type"))
}
@ -435,7 +436,7 @@ func TestRenderString(t *testing.T) {
Data: []any{"manu", 2},
}).Render(w)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, "hola manu 2", w.Body.String())
assert.Equal(t, "text/plain; charset=utf-8", w.Header().Get("Content-Type"))
}
@ -448,7 +449,7 @@ func TestRenderStringLenZero(t *testing.T) {
Data: []any{},
}).Render(w)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, "hola %s %d", w.Body.String())
assert.Equal(t, "text/plain; charset=utf-8", w.Header().Get("Content-Type"))
}
@ -464,7 +465,7 @@ func TestRenderHTMLTemplate(t *testing.T) {
err := instance.Render(w)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, "Hello alexandernyquist", w.Body.String())
assert.Equal(t, "text/html; charset=utf-8", w.Header().Get("Content-Type"))
}
@ -480,7 +481,7 @@ func TestRenderHTMLTemplateEmptyName(t *testing.T) {
err := instance.Render(w)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, "Hello alexandernyquist", w.Body.String())
assert.Equal(t, "text/html; charset=utf-8", w.Header().Get("Content-Type"))
}
@ -499,7 +500,7 @@ func TestRenderHTMLDebugFiles(t *testing.T) {
err := instance.Render(w)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, "<h1>Hello thinkerou</h1>", w.Body.String())
assert.Equal(t, "text/html; charset=utf-8", w.Header().Get("Content-Type"))
}
@ -518,7 +519,7 @@ func TestRenderHTMLDebugGlob(t *testing.T) {
err := instance.Render(w)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, "<h1>Hello thinkerou</h1>", w.Body.String())
assert.Equal(t, "text/html; charset=utf-8", w.Header().Get("Content-Type"))
}
@ -548,7 +549,7 @@ func TestRenderReader(t *testing.T) {
Headers: headers,
}).Render(w)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, body, w.Body.String())
assert.Equal(t, "image/png", w.Header().Get("Content-Type"))
assert.Equal(t, strconv.Itoa(len(body)), w.Header().Get("Content-Length"))
@ -571,7 +572,7 @@ func TestRenderReaderNoContentLength(t *testing.T) {
Headers: headers,
}).Render(w)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, body, w.Body.String())
assert.Equal(t, "image/png", w.Header().Get("Content-Type"))
assert.NotContains(t, "Content-Length", w.Header())
@ -588,6 +589,6 @@ func TestRenderWriteError(t *testing.T) {
ResponseRecorder: httptest.NewRecorder(),
}
err := r.Render(ew)
assert.NotNil(t, err)
require.Error(t, err)
assert.Equal(t, `write "my-prefix:" error`, err.Error())
}

View File

@ -10,6 +10,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// TODO
@ -95,13 +96,13 @@ func TestResponseWriterWrite(t *testing.T) {
assert.Equal(t, http.StatusOK, w.Status())
assert.Equal(t, http.StatusOK, testWriter.Code)
assert.Equal(t, "hola", testWriter.Body.String())
assert.NoError(t, err)
require.NoError(t, err)
n, err = w.Write([]byte(" adios"))
assert.Equal(t, 6, n)
assert.Equal(t, 10, w.Size())
assert.Equal(t, "hola adios", testWriter.Body.String())
assert.NoError(t, err)
require.NoError(t, err)
}
func TestResponseWriterHijack(t *testing.T) {
@ -112,7 +113,7 @@ func TestResponseWriterHijack(t *testing.T) {
assert.Panics(t, func() {
_, _, err := w.Hijack()
assert.NoError(t, err)
require.NoError(t, err)
})
assert.True(t, w.Written())
@ -135,7 +136,7 @@ func TestResponseWriterFlush(t *testing.T) {
// should return 500
resp, err := http.Get(testServer.URL)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, http.StatusInternalServerError, resp.StatusCode)
}

View File

@ -13,6 +13,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type header struct {
@ -386,7 +387,7 @@ func TestRouteStaticFile(t *testing.T) {
}
defer os.Remove(f.Name())
_, err = f.WriteString("Gin Web Framework")
assert.NoError(t, err)
require.NoError(t, err)
f.Close()
dir, filename := filepath.Split(f.Name())
@ -421,7 +422,7 @@ func TestRouteStaticFileFS(t *testing.T) {
}
defer os.Remove(f.Name())
_, err = f.WriteString("Gin Web Framework")
assert.NoError(t, err)
require.NoError(t, err)
f.Close()
dir, filename := filepath.Split(f.Name())
@ -484,7 +485,7 @@ func TestRouterMiddlewareAndStatic(t *testing.T) {
// 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.NotEqual(t, w.Header().Get("Last-Modified"), "Mon, 02 Jan 2006 15:04:05 MST")
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"))
}

View File

@ -145,6 +145,6 @@ func TestMarshalXMLforH(t *testing.T) {
}
func TestIsASCII(t *testing.T) {
assert.Equal(t, isASCII("test"), true)
assert.Equal(t, isASCII("🧡💛💚💙💜"), false)
assert.True(t, isASCII("test"))
assert.False(t, isASCII("🧡💛💚💙💜"))
}