Compare commits
No commits in common. "c4b087d990949ba10e48d26ebf0af0638a55d210" and "22ec4deb4aa929256d3749050761323a06f9f711" have entirely different histories.
c4b087d990
...
22ec4deb4a
23
gin/b/b.go
23
gin/b/b.go
|
@ -1,8 +1,8 @@
|
||||||
package b
|
package b
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.hpds.cc/Component/gin_valid.git/gin/binding"
|
"git.ningdatech.com/ningda/gin_valid/gin/binding"
|
||||||
"git.hpds.cc/Component/gin_valid.git/go-playground/validator/v10"
|
"git.ningdatech.com/ningda/gin_valid/go-playground/validator/v10"
|
||||||
"mime"
|
"mime"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
@ -11,7 +11,7 @@ type ValidError struct {
|
||||||
ErrString string
|
ErrString string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e ValidError) Error() string {
|
func (e *ValidError) Error() string {
|
||||||
return e.ErrString
|
return e.ErrString
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,22 +21,17 @@ func ShouldBind(req *http.Request, obj interface{}) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
b := binding.Default(req.Method, content)
|
b := binding.Default(req.Method, content)
|
||||||
return ShouldBindWith(req, obj, b)
|
err = ShouldBindWith(req, obj, b)
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func ShouldBindWith(req *http.Request, obj interface{}, b binding.Binding) error {
|
|
||||||
err := b.Bind(req, obj)
|
|
||||||
errs, ok := err.(validator.ValidationErrors)
|
errs, ok := err.(validator.ValidationErrors)
|
||||||
if !ok {
|
if !ok {
|
||||||
// 非validator.ValidationErrors类型错误直接返回
|
// 非validator.ValidationErrors类型错误直接返回
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err0 := errs.Translate(binding.ValidTrans)
|
return errs.Translate(binding.ValidTrans)
|
||||||
if err0 != nil {
|
}
|
||||||
return ValidError{ErrString: err0.Error()}
|
|
||||||
}
|
func ShouldBindWith(req *http.Request, obj interface{}, b binding.Binding) error {
|
||||||
return nil
|
return b.Bind(req, obj)
|
||||||
}
|
}
|
||||||
func ShouldBindJSON(req *http.Request, obj interface{}) error {
|
func ShouldBindJSON(req *http.Request, obj interface{}) error {
|
||||||
return ShouldBindWith(req, obj, binding.JSON)
|
return ShouldBindWith(req, obj, binding.JSON)
|
||||||
|
|
|
@ -5,10 +5,10 @@
|
||||||
package binding
|
package binding
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.hpds.cc/Component/gin_valid.git/go-playground/locales/zh"
|
"git.ningdatech.com/ningda/gin_valid/go-playground/locales/zh"
|
||||||
ut "git.hpds.cc/Component/gin_valid.git/go-playground/universal-translator"
|
ut "git.ningdatech.com/ningda/gin_valid/go-playground/universal-translator"
|
||||||
"git.hpds.cc/Component/gin_valid.git/go-playground/validator/v10"
|
"git.ningdatech.com/ningda/gin_valid/go-playground/validator/v10"
|
||||||
zhTrans "git.hpds.cc/Component/gin_valid.git/go-playground/validator/v10/translations/zh"
|
zhTrans "git.ningdatech.com/ningda/gin_valid/go-playground/validator/v10/translations/zh"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
|
@ -12,8 +12,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.hpds.cc/Component/gin_valid.git/gin/internal/bytesconv"
|
"git.ningdatech.com/ningda/gin_valid/gin/internal/bytesconv"
|
||||||
"git.hpds.cc/Component/gin_valid.git/gin/internal/json"
|
"git.ningdatech.com/ningda/gin_valid/gin/internal/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
var errUnknownType = errors.New("unknown type")
|
var errUnknownType = errors.New("unknown type")
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
// Copyright 2019 Gin Core Team. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package binding
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
var form = map[string][]string{
|
||||||
|
"name": {"mike"},
|
||||||
|
"friends": {"anna", "nicole"},
|
||||||
|
"id_number": {"12345678"},
|
||||||
|
"id_date": {"2018-01-20"},
|
||||||
|
}
|
||||||
|
|
||||||
|
type structFull struct {
|
||||||
|
Name string `form:"name"`
|
||||||
|
Age int `form:"age,default=25"`
|
||||||
|
Friends []string `form:"friends"`
|
||||||
|
ID *struct {
|
||||||
|
Number string `form:"id_number"`
|
||||||
|
DateOfIssue time.Time `form:"id_date" time_format:"2006-01-02" time_utc:"true"`
|
||||||
|
}
|
||||||
|
Nationality *string `form:"nationality"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkMapFormFull(b *testing.B) {
|
||||||
|
var s structFull
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
err := mapForm(&s, form)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("Error on a form mapping")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b.StopTimer()
|
||||||
|
|
||||||
|
t := b
|
||||||
|
assert.Equal(t, "mike", s.Name)
|
||||||
|
assert.Equal(t, 25, s.Age)
|
||||||
|
assert.Equal(t, []string{"anna", "nicole"}, s.Friends)
|
||||||
|
assert.Equal(t, "12345678", s.ID.Number)
|
||||||
|
assert.Equal(t, time.Date(2018, 1, 20, 0, 0, 0, 0, time.UTC), s.ID.DateOfIssue)
|
||||||
|
assert.Nil(t, s.Nationality)
|
||||||
|
}
|
||||||
|
|
||||||
|
type structName struct {
|
||||||
|
Name string `form:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkMapFormName(b *testing.B) {
|
||||||
|
var s structName
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
err := mapForm(&s, form)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("Error on a form mapping")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b.StopTimer()
|
||||||
|
|
||||||
|
t := b
|
||||||
|
assert.Equal(t, "mike", s.Name)
|
||||||
|
}
|
|
@ -0,0 +1,281 @@
|
||||||
|
// Copyright 2019 Gin Core Team. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package binding
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMappingBaseTypes(t *testing.T) {
|
||||||
|
intPtr := func(i int) *int {
|
||||||
|
return &i
|
||||||
|
}
|
||||||
|
for _, tt := range []struct {
|
||||||
|
name string
|
||||||
|
value interface{}
|
||||||
|
form string
|
||||||
|
expect interface{}
|
||||||
|
}{
|
||||||
|
{"base type", struct{ F int }{}, "9", int(9)},
|
||||||
|
{"base type", struct{ F int8 }{}, "9", int8(9)},
|
||||||
|
{"base type", struct{ F int16 }{}, "9", int16(9)},
|
||||||
|
{"base type", struct{ F int32 }{}, "9", int32(9)},
|
||||||
|
{"base type", struct{ F int64 }{}, "9", int64(9)},
|
||||||
|
{"base type", struct{ F uint }{}, "9", uint(9)},
|
||||||
|
{"base type", struct{ F uint8 }{}, "9", uint8(9)},
|
||||||
|
{"base type", struct{ F uint16 }{}, "9", uint16(9)},
|
||||||
|
{"base type", struct{ F uint32 }{}, "9", uint32(9)},
|
||||||
|
{"base type", struct{ F uint64 }{}, "9", uint64(9)},
|
||||||
|
{"base type", struct{ F bool }{}, "True", true},
|
||||||
|
{"base type", struct{ F float32 }{}, "9.1", float32(9.1)},
|
||||||
|
{"base type", struct{ F float64 }{}, "9.1", float64(9.1)},
|
||||||
|
{"base type", struct{ F string }{}, "test", string("test")},
|
||||||
|
{"base type", struct{ F *int }{}, "9", intPtr(9)},
|
||||||
|
|
||||||
|
// zero values
|
||||||
|
{"zero value", struct{ F int }{}, "", int(0)},
|
||||||
|
{"zero value", struct{ F uint }{}, "", uint(0)},
|
||||||
|
{"zero value", struct{ F bool }{}, "", false},
|
||||||
|
{"zero value", struct{ F float32 }{}, "", float32(0)},
|
||||||
|
} {
|
||||||
|
tp := reflect.TypeOf(tt.value)
|
||||||
|
testName := tt.name + ":" + tp.Field(0).Type.String()
|
||||||
|
|
||||||
|
val := reflect.New(reflect.TypeOf(tt.value))
|
||||||
|
val.Elem().Set(reflect.ValueOf(tt.value))
|
||||||
|
|
||||||
|
field := val.Elem().Type().Field(0)
|
||||||
|
|
||||||
|
_, err := mapping(val, emptyField, formSource{field.Name: {tt.form}}, "form")
|
||||||
|
assert.NoError(t, err, testName)
|
||||||
|
|
||||||
|
actual := val.Elem().Field(0).Interface()
|
||||||
|
assert.Equal(t, tt.expect, actual, testName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMappingDefault(t *testing.T) {
|
||||||
|
var s struct {
|
||||||
|
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)
|
||||||
|
|
||||||
|
assert.Equal(t, 9, s.Int)
|
||||||
|
assert.Equal(t, []int{9}, s.Slice)
|
||||||
|
assert.Equal(t, [1]int{9}, s.Array)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMappingSkipField(t *testing.T) {
|
||||||
|
var s struct {
|
||||||
|
A int
|
||||||
|
}
|
||||||
|
err := mappingByPtr(&s, formSource{}, "form")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, 0, s.A)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMappingIgnoreField(t *testing.T) {
|
||||||
|
var s struct {
|
||||||
|
A int `form:"A"`
|
||||||
|
B int `form:"-"`
|
||||||
|
}
|
||||||
|
err := mappingByPtr(&s, formSource{"A": {"9"}, "B": {"9"}}, "form")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, 9, s.A)
|
||||||
|
assert.Equal(t, 0, s.B)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMappingUnexportedField(t *testing.T) {
|
||||||
|
var s struct {
|
||||||
|
A int `form:"a"`
|
||||||
|
b int `form:"b"`
|
||||||
|
}
|
||||||
|
err := mappingByPtr(&s, formSource{"a": {"9"}, "b": {"9"}}, "form")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, 9, s.A)
|
||||||
|
assert.Equal(t, 0, s.b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMappingPrivateField(t *testing.T) {
|
||||||
|
var s struct {
|
||||||
|
f int `form:"field"`
|
||||||
|
}
|
||||||
|
err := mappingByPtr(&s, formSource{"field": {"6"}}, "form")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, int(0), s.f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMappingUnknownFieldType(t *testing.T) {
|
||||||
|
var s struct {
|
||||||
|
U uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
err := mappingByPtr(&s, formSource{"U": {"unknown"}}, "form")
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Equal(t, errUnknownType, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMappingURI(t *testing.T) {
|
||||||
|
var s struct {
|
||||||
|
F int `uri:"field"`
|
||||||
|
}
|
||||||
|
err := mapUri(&s, map[string][]string{"field": {"6"}})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, int(6), s.F)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMappingForm(t *testing.T) {
|
||||||
|
var s struct {
|
||||||
|
F int `form:"field"`
|
||||||
|
}
|
||||||
|
err := mapForm(&s, map[string][]string{"field": {"6"}})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, int(6), s.F)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMappingTime(t *testing.T) {
|
||||||
|
var s struct {
|
||||||
|
Time time.Time
|
||||||
|
LocalTime time.Time `time_format:"2006-01-02"`
|
||||||
|
ZeroValue time.Time
|
||||||
|
CSTTime time.Time `time_format:"2006-01-02" time_location:"Asia/Shanghai"`
|
||||||
|
UTCTime time.Time `time_format:"2006-01-02" time_utc:"1"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
time.Local, err = time.LoadLocation("Europe/Berlin")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = mapForm(&s, map[string][]string{
|
||||||
|
"Time": {"2019-01-20T16:02:58Z"},
|
||||||
|
"LocalTime": {"2019-01-20"},
|
||||||
|
"ZeroValue": {},
|
||||||
|
"CSTTime": {"2019-01-20"},
|
||||||
|
"UTCTime": {"2019-01-20"},
|
||||||
|
})
|
||||||
|
assert.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())
|
||||||
|
assert.Equal(t, "2019-01-19 23:00:00 +0000 UTC", s.LocalTime.UTC().String())
|
||||||
|
assert.Equal(t, "0001-01-01 00:00:00 +0000 UTC", s.ZeroValue.String())
|
||||||
|
assert.Equal(t, "2019-01-20 00:00:00 +0800 CST", s.CSTTime.String())
|
||||||
|
assert.Equal(t, "2019-01-19 16:00:00 +0000 UTC", s.CSTTime.UTC().String())
|
||||||
|
assert.Equal(t, "2019-01-20 00:00:00 +0000 UTC", s.UTCTime.String())
|
||||||
|
|
||||||
|
// wrong location
|
||||||
|
var wrongLoc struct {
|
||||||
|
Time time.Time `time_location:"wrong"`
|
||||||
|
}
|
||||||
|
err = mapForm(&wrongLoc, map[string][]string{"Time": {"2019-01-20T16:02:58Z"}})
|
||||||
|
assert.Error(t, err)
|
||||||
|
|
||||||
|
// wrong time value
|
||||||
|
var wrongTime struct {
|
||||||
|
Time time.Time
|
||||||
|
}
|
||||||
|
err = mapForm(&wrongTime, map[string][]string{"Time": {"wrong"}})
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMappingTimeDuration(t *testing.T) {
|
||||||
|
var s struct {
|
||||||
|
D time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// ok
|
||||||
|
err := mappingByPtr(&s, formSource{"D": {"5s"}}, "form")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 5*time.Second, s.D)
|
||||||
|
|
||||||
|
// error
|
||||||
|
err = mappingByPtr(&s, formSource{"D": {"wrong"}}, "form")
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMappingSlice(t *testing.T) {
|
||||||
|
var s struct {
|
||||||
|
Slice []int `form:"slice,default=9"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// default value
|
||||||
|
err := mappingByPtr(&s, formSource{}, "form")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, []int{9}, s.Slice)
|
||||||
|
|
||||||
|
// ok
|
||||||
|
err = mappingByPtr(&s, formSource{"slice": {"3", "4"}}, "form")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, []int{3, 4}, s.Slice)
|
||||||
|
|
||||||
|
// error
|
||||||
|
err = mappingByPtr(&s, formSource{"slice": {"wrong"}}, "form")
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMappingArray(t *testing.T) {
|
||||||
|
var s struct {
|
||||||
|
Array [2]int `form:"array,default=9"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// wrong default
|
||||||
|
err := mappingByPtr(&s, formSource{}, "form")
|
||||||
|
assert.Error(t, err)
|
||||||
|
|
||||||
|
// ok
|
||||||
|
err = mappingByPtr(&s, formSource{"array": {"3", "4"}}, "form")
|
||||||
|
assert.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)
|
||||||
|
|
||||||
|
// error - wrong value
|
||||||
|
err = mappingByPtr(&s, formSource{"array": {"wrong"}}, "form")
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMappingStructField(t *testing.T) {
|
||||||
|
var s struct {
|
||||||
|
J struct {
|
||||||
|
I int
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err := mappingByPtr(&s, formSource{"J": {`{"I": 9}`}}, "form")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 9, s.J.I)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMappingMapField(t *testing.T) {
|
||||||
|
var s struct {
|
||||||
|
M map[string]int
|
||||||
|
}
|
||||||
|
|
||||||
|
err := mappingByPtr(&s, formSource{"M": {`{"one": 1}`}}, "form")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, map[string]int{"one": 1}, s.M)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMappingIgnoredCircularRef(t *testing.T) {
|
||||||
|
type S struct {
|
||||||
|
S *S `form:"-"`
|
||||||
|
}
|
||||||
|
var s S
|
||||||
|
|
||||||
|
err := mappingByPtr(&s, formSource{}, "form")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
|
@ -10,7 +10,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"git.hpds.cc/Component/gin_valid.git/gin/internal/json"
|
"git.ningdatech.com/ningda/gin_valid/gin/internal/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
// EnableDecoderUseNumber is used to call the UseNumber method on the JSON
|
// EnableDecoderUseNumber is used to call the UseNumber method on the JSON
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
// Copyright 2019 Gin Core Team. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package binding
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestJSONBindingBindBody(t *testing.T) {
|
||||||
|
var s struct {
|
||||||
|
Foo string `json:"foo"`
|
||||||
|
}
|
||||||
|
err := jsonBinding{}.BindBody([]byte(`{"foo": "FOO"}`), &s)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, "FOO", s.Foo)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestJSONBindingBindBodyMap(t *testing.T) {
|
||||||
|
s := make(map[string]string)
|
||||||
|
err := jsonBinding{}.BindBody([]byte(`{"foo": "FOO","hello":"world"}`), &s)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Len(t, s, 2)
|
||||||
|
assert.Equal(t, "FOO", s["foo"])
|
||||||
|
assert.Equal(t, "world", s["hello"])
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
// Copyright 2019 Gin Core Team. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !nomsgpack
|
||||||
|
|
||||||
|
package binding
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/ugorji/go/codec"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMsgpackBindingBindBody(t *testing.T) {
|
||||||
|
type teststruct struct {
|
||||||
|
Foo string `msgpack:"foo"`
|
||||||
|
}
|
||||||
|
var s teststruct
|
||||||
|
err := msgpackBinding{}.BindBody(msgpackBody(t, teststruct{"FOO"}), &s)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, "FOO", s.Foo)
|
||||||
|
}
|
||||||
|
|
||||||
|
func msgpackBody(t *testing.T, obj interface{}) []byte {
|
||||||
|
var bs bytes.Buffer
|
||||||
|
h := &codec.MsgpackHandle{}
|
||||||
|
err := codec.NewEncoder(&bs, h).Encode(obj)
|
||||||
|
require.NoError(t, err)
|
||||||
|
return bs.Bytes()
|
||||||
|
}
|
|
@ -0,0 +1,138 @@
|
||||||
|
// Copyright 2019 Gin Core Team. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package binding
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io/ioutil"
|
||||||
|
"mime/multipart"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFormMultipartBindingBindOneFile(t *testing.T) {
|
||||||
|
var s struct {
|
||||||
|
FileValue multipart.FileHeader `form:"file"`
|
||||||
|
FilePtr *multipart.FileHeader `form:"file"`
|
||||||
|
SliceValues []multipart.FileHeader `form:"file"`
|
||||||
|
SlicePtrs []*multipart.FileHeader `form:"file"`
|
||||||
|
ArrayValues [1]multipart.FileHeader `form:"file"`
|
||||||
|
ArrayPtrs [1]*multipart.FileHeader `form:"file"`
|
||||||
|
}
|
||||||
|
file := testFile{"file", "file1", []byte("hello")}
|
||||||
|
|
||||||
|
req := createRequestMultipartFiles(t, file)
|
||||||
|
err := FormMultipart.Bind(req, &s)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assertMultipartFileHeader(t, &s.FileValue, file)
|
||||||
|
assertMultipartFileHeader(t, s.FilePtr, file)
|
||||||
|
assert.Len(t, s.SliceValues, 1)
|
||||||
|
assertMultipartFileHeader(t, &s.SliceValues[0], file)
|
||||||
|
assert.Len(t, s.SlicePtrs, 1)
|
||||||
|
assertMultipartFileHeader(t, s.SlicePtrs[0], file)
|
||||||
|
assertMultipartFileHeader(t, &s.ArrayValues[0], file)
|
||||||
|
assertMultipartFileHeader(t, s.ArrayPtrs[0], file)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFormMultipartBindingBindTwoFiles(t *testing.T) {
|
||||||
|
var s struct {
|
||||||
|
SliceValues []multipart.FileHeader `form:"file"`
|
||||||
|
SlicePtrs []*multipart.FileHeader `form:"file"`
|
||||||
|
ArrayValues [2]multipart.FileHeader `form:"file"`
|
||||||
|
ArrayPtrs [2]*multipart.FileHeader `form:"file"`
|
||||||
|
}
|
||||||
|
files := []testFile{
|
||||||
|
{"file", "file1", []byte("hello")},
|
||||||
|
{"file", "file2", []byte("world")},
|
||||||
|
}
|
||||||
|
|
||||||
|
req := createRequestMultipartFiles(t, files...)
|
||||||
|
err := FormMultipart.Bind(req, &s)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Len(t, s.SliceValues, len(files))
|
||||||
|
assert.Len(t, s.SlicePtrs, len(files))
|
||||||
|
assert.Len(t, s.ArrayValues, len(files))
|
||||||
|
assert.Len(t, s.ArrayPtrs, len(files))
|
||||||
|
|
||||||
|
for i, file := range files {
|
||||||
|
assertMultipartFileHeader(t, &s.SliceValues[i], file)
|
||||||
|
assertMultipartFileHeader(t, s.SlicePtrs[i], file)
|
||||||
|
assertMultipartFileHeader(t, &s.ArrayValues[i], file)
|
||||||
|
assertMultipartFileHeader(t, s.ArrayPtrs[i], file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFormMultipartBindingBindError(t *testing.T) {
|
||||||
|
files := []testFile{
|
||||||
|
{"file", "file1", []byte("hello")},
|
||||||
|
{"file", "file2", []byte("world")},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range []struct {
|
||||||
|
name string
|
||||||
|
s interface{}
|
||||||
|
}{
|
||||||
|
{"wrong type", &struct {
|
||||||
|
Files int `form:"file"`
|
||||||
|
}{}},
|
||||||
|
{"wrong array size", &struct {
|
||||||
|
Files [1]*multipart.FileHeader `form:"file"`
|
||||||
|
}{}},
|
||||||
|
{"wrong slice type", &struct {
|
||||||
|
Files []int `form:"file"`
|
||||||
|
}{}},
|
||||||
|
} {
|
||||||
|
req := createRequestMultipartFiles(t, files...)
|
||||||
|
err := FormMultipart.Bind(req, tt.s)
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type testFile struct {
|
||||||
|
Fieldname string
|
||||||
|
Filename string
|
||||||
|
Content []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func createRequestMultipartFiles(t *testing.T, files ...testFile) *http.Request {
|
||||||
|
var body bytes.Buffer
|
||||||
|
|
||||||
|
mw := multipart.NewWriter(&body)
|
||||||
|
for _, file := range files {
|
||||||
|
fw, err := mw.CreateFormFile(file.Fieldname, file.Filename)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
n, err := fw.Write(file.Content)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, len(file.Content), n)
|
||||||
|
}
|
||||||
|
err := mw.Close()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
req, err := http.NewRequest("POST", "/", &body)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+mw.Boundary())
|
||||||
|
return req
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertMultipartFileHeader(t *testing.T, fh *multipart.FileHeader, file testFile) {
|
||||||
|
assert.Equal(t, file.Filename, fh.Filename)
|
||||||
|
// assert.Equal(t, int64(len(file.Content)), fh.Size) // fh.Size does not exist on go1.8
|
||||||
|
|
||||||
|
fl, err := fh.Open()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(fl)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, string(file.Content), string(body))
|
||||||
|
|
||||||
|
err = fl.Close()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
|
@ -0,0 +1,228 @@
|
||||||
|
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package binding
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"go-playground/validator/v10"
|
||||||
|
)
|
||||||
|
|
||||||
|
type testInterface interface {
|
||||||
|
String() string
|
||||||
|
}
|
||||||
|
|
||||||
|
type substructNoValidation struct {
|
||||||
|
IString string
|
||||||
|
IInt int
|
||||||
|
}
|
||||||
|
|
||||||
|
type mapNoValidationSub map[string]substructNoValidation
|
||||||
|
|
||||||
|
type structNoValidationValues struct {
|
||||||
|
substructNoValidation
|
||||||
|
|
||||||
|
Boolean bool
|
||||||
|
|
||||||
|
Uinteger uint
|
||||||
|
Integer int
|
||||||
|
Integer8 int8
|
||||||
|
Integer16 int16
|
||||||
|
Integer32 int32
|
||||||
|
Integer64 int64
|
||||||
|
Uinteger8 uint8
|
||||||
|
Uinteger16 uint16
|
||||||
|
Uinteger32 uint32
|
||||||
|
Uinteger64 uint64
|
||||||
|
|
||||||
|
Float32 float32
|
||||||
|
Float64 float64
|
||||||
|
|
||||||
|
String string
|
||||||
|
|
||||||
|
Date time.Time
|
||||||
|
|
||||||
|
Struct substructNoValidation
|
||||||
|
InlinedStruct struct {
|
||||||
|
String []string
|
||||||
|
Integer int
|
||||||
|
}
|
||||||
|
|
||||||
|
IntSlice []int
|
||||||
|
IntPointerSlice []*int
|
||||||
|
StructPointerSlice []*substructNoValidation
|
||||||
|
StructSlice []substructNoValidation
|
||||||
|
InterfaceSlice []testInterface
|
||||||
|
|
||||||
|
UniversalInterface interface{}
|
||||||
|
CustomInterface testInterface
|
||||||
|
|
||||||
|
FloatMap map[string]float32
|
||||||
|
StructMap mapNoValidationSub
|
||||||
|
}
|
||||||
|
|
||||||
|
func createNoValidationValues() structNoValidationValues {
|
||||||
|
integer := 1
|
||||||
|
s := structNoValidationValues{
|
||||||
|
Boolean: true,
|
||||||
|
Uinteger: 1 << 29,
|
||||||
|
Integer: -10000,
|
||||||
|
Integer8: 120,
|
||||||
|
Integer16: -20000,
|
||||||
|
Integer32: 1 << 29,
|
||||||
|
Integer64: 1 << 61,
|
||||||
|
Uinteger8: 250,
|
||||||
|
Uinteger16: 50000,
|
||||||
|
Uinteger32: 1 << 31,
|
||||||
|
Uinteger64: 1 << 62,
|
||||||
|
Float32: 123.456,
|
||||||
|
Float64: 123.456789,
|
||||||
|
String: "text",
|
||||||
|
Date: time.Time{},
|
||||||
|
CustomInterface: &bytes.Buffer{},
|
||||||
|
Struct: substructNoValidation{},
|
||||||
|
IntSlice: []int{-3, -2, 1, 0, 1, 2, 3},
|
||||||
|
IntPointerSlice: []*int{&integer},
|
||||||
|
StructSlice: []substructNoValidation{},
|
||||||
|
UniversalInterface: 1.2,
|
||||||
|
FloatMap: map[string]float32{
|
||||||
|
"foo": 1.23,
|
||||||
|
"bar": 232.323,
|
||||||
|
},
|
||||||
|
StructMap: mapNoValidationSub{
|
||||||
|
"foo": substructNoValidation{},
|
||||||
|
"bar": substructNoValidation{},
|
||||||
|
},
|
||||||
|
// StructPointerSlice []noValidationSub
|
||||||
|
// InterfaceSlice []testInterface
|
||||||
|
}
|
||||||
|
s.InlinedStruct.Integer = 1000
|
||||||
|
s.InlinedStruct.String = []string{"first", "second"}
|
||||||
|
s.IString = "substring"
|
||||||
|
s.IInt = 987654
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidateNoValidationValues(t *testing.T) {
|
||||||
|
origin := createNoValidationValues()
|
||||||
|
test := createNoValidationValues()
|
||||||
|
empty := structNoValidationValues{}
|
||||||
|
|
||||||
|
assert.Nil(t, validate(test))
|
||||||
|
assert.Nil(t, validate(&test))
|
||||||
|
assert.Nil(t, validate(empty))
|
||||||
|
assert.Nil(t, validate(&empty))
|
||||||
|
|
||||||
|
assert.Equal(t, origin, test)
|
||||||
|
}
|
||||||
|
|
||||||
|
type structNoValidationPointer struct {
|
||||||
|
substructNoValidation
|
||||||
|
|
||||||
|
Boolean bool
|
||||||
|
|
||||||
|
Uinteger *uint
|
||||||
|
Integer *int
|
||||||
|
Integer8 *int8
|
||||||
|
Integer16 *int16
|
||||||
|
Integer32 *int32
|
||||||
|
Integer64 *int64
|
||||||
|
Uinteger8 *uint8
|
||||||
|
Uinteger16 *uint16
|
||||||
|
Uinteger32 *uint32
|
||||||
|
Uinteger64 *uint64
|
||||||
|
|
||||||
|
Float32 *float32
|
||||||
|
Float64 *float64
|
||||||
|
|
||||||
|
String *string
|
||||||
|
|
||||||
|
Date *time.Time
|
||||||
|
|
||||||
|
Struct *substructNoValidation
|
||||||
|
|
||||||
|
IntSlice *[]int
|
||||||
|
IntPointerSlice *[]*int
|
||||||
|
StructPointerSlice *[]*substructNoValidation
|
||||||
|
StructSlice *[]substructNoValidation
|
||||||
|
InterfaceSlice *[]testInterface
|
||||||
|
|
||||||
|
FloatMap *map[string]float32
|
||||||
|
StructMap *mapNoValidationSub
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidateNoValidationPointers(t *testing.T) {
|
||||||
|
//origin := createNoValidation_values()
|
||||||
|
//test := createNoValidation_values()
|
||||||
|
empty := structNoValidationPointer{}
|
||||||
|
|
||||||
|
//assert.Nil(t, validate(test))
|
||||||
|
//assert.Nil(t, validate(&test))
|
||||||
|
assert.Nil(t, validate(empty))
|
||||||
|
assert.Nil(t, validate(&empty))
|
||||||
|
|
||||||
|
//assert.Equal(t, origin, test)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Object map[string]interface{}
|
||||||
|
|
||||||
|
func TestValidatePrimitives(t *testing.T) {
|
||||||
|
obj := Object{"foo": "bar", "bar": 1}
|
||||||
|
assert.NoError(t, validate(obj))
|
||||||
|
assert.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))
|
||||||
|
|
||||||
|
nu := 10
|
||||||
|
assert.NoError(t, validate(nu))
|
||||||
|
assert.NoError(t, validate(&nu))
|
||||||
|
assert.Equal(t, 10, nu)
|
||||||
|
|
||||||
|
str := "value"
|
||||||
|
assert.NoError(t, validate(str))
|
||||||
|
assert.NoError(t, validate(&str))
|
||||||
|
assert.Equal(t, "value", str)
|
||||||
|
}
|
||||||
|
|
||||||
|
// structCustomValidation is a helper struct we use to check that
|
||||||
|
// custom validation can be registered on it.
|
||||||
|
// The `notone` binding directive is for custom validation and registered later.
|
||||||
|
type structCustomValidation struct {
|
||||||
|
Integer int `binding:"notone"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func notOne(f1 validator.FieldLevel) bool {
|
||||||
|
if val, ok := f1.Field().Interface().(int); ok {
|
||||||
|
return val != 1
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidatorEngine(t *testing.T) {
|
||||||
|
// This validates that the function `notOne` matches
|
||||||
|
// the expected function signature by `defaultValidator`
|
||||||
|
// and by extension the validator library.
|
||||||
|
engine, ok := Validator.Engine().(*validator.Validate)
|
||||||
|
assert.True(t, ok)
|
||||||
|
|
||||||
|
err := engine.RegisterValidation("notone", notOne)
|
||||||
|
// Check that we can register custom validation without error
|
||||||
|
assert.Nil(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)
|
||||||
|
// Check that the error matches expectation
|
||||||
|
assert.Error(t, errs, "", "", "notone")
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
// Copyright 2019 Gin Core Team. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package binding
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestXMLBindingBindBody(t *testing.T) {
|
||||||
|
var s struct {
|
||||||
|
Foo string `xml:"foo"`
|
||||||
|
}
|
||||||
|
xmlBody := `<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<root>
|
||||||
|
<foo>FOO</foo>
|
||||||
|
</root>`
|
||||||
|
err := xmlBinding{}.BindBody([]byte(xmlBody), &s)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, "FOO", s.Foo)
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
// Copyright 2019 Gin Core Team. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package binding
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestYAMLBindingBindBody(t *testing.T) {
|
||||||
|
var s struct {
|
||||||
|
Foo string `yaml:"foo"`
|
||||||
|
}
|
||||||
|
err := yamlBinding{}.BindBody([]byte("foo: FOO"), &s)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, "FOO", s.Foo)
|
||||||
|
}
|
|
@ -86,7 +86,7 @@ type TransValidError struct {
|
||||||
func (e TransValidError) Error() string {
|
func (e TransValidError) Error() string {
|
||||||
return e.ErrorString
|
return e.ErrorString
|
||||||
}
|
}
|
||||||
func (ve ValidationErrors) Translate(ut ut.Translator) error {
|
func (ve ValidationErrors) Translate(ut ut.Translator) TransValidError {
|
||||||
var result TransValidError
|
var result TransValidError
|
||||||
var fe *fieldError
|
var fe *fieldError
|
||||||
if len(ve) == 0 {
|
if len(ve) == 0 {
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -1,4 +1,4 @@
|
||||||
module git.hpds.cc/Component/gin_valid.git
|
module git.ningdatech.com/ningda/gin_valid
|
||||||
|
|
||||||
go 1.13
|
go 1.13
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue