mirror of
https://github.com/gin-gonic/gin.git
synced 2025-10-16 21:32:11 +08:00
212 lines
8.6 KiB
Go
212 lines
8.6 KiB
Go
// Copyright 2020 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 (
|
|
"errors"
|
|
"testing"
|
|
|
|
"github.com/go-playground/validator/v10"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestSliceFieldError(t *testing.T) {
|
|
var fe validator.FieldError = dummyFieldError{msg: "test error"}
|
|
|
|
var err SliceFieldError = sliceFieldError{fe, 10}
|
|
assert.Equal(t, 10, err.Index())
|
|
assert.Equal(t, "[10]: test error", err.Error())
|
|
assert.Equal(t, fe, errors.Unwrap(err))
|
|
}
|
|
|
|
func TestMapFieldError(t *testing.T) {
|
|
var fe validator.FieldError = dummyFieldError{msg: "test error"}
|
|
|
|
var err MapFieldError = mapFieldError{fe, "test key"}
|
|
assert.Equal(t, "test key", err.Key())
|
|
assert.Equal(t, "[test key]: test error", err.Error())
|
|
assert.Equal(t, fe, errors.Unwrap(err))
|
|
|
|
err = mapFieldError{fe, 123}
|
|
assert.Equal(t, 123, err.Key())
|
|
assert.Equal(t, "[123]: test error", err.Error())
|
|
assert.Equal(t, fe, errors.Unwrap(err))
|
|
}
|
|
|
|
type dummyFieldError struct {
|
|
validator.FieldError
|
|
msg string
|
|
}
|
|
|
|
func (fe dummyFieldError) Error() string {
|
|
return fe.msg
|
|
}
|
|
|
|
func TestDefaultValidator(t *testing.T) {
|
|
type exampleStruct struct {
|
|
A string `binding:"max=8"`
|
|
B int `binding:"gt=0"`
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
v *defaultValidator
|
|
obj interface{}
|
|
wantErr bool
|
|
}{
|
|
{"validate nil obj", &defaultValidator{}, nil, false},
|
|
{"validate int obj", &defaultValidator{}, 3, false},
|
|
{"validate struct failed-1", &defaultValidator{}, exampleStruct{A: "123456789", B: 1}, true},
|
|
{"validate struct failed-2", &defaultValidator{}, exampleStruct{A: "12345678", B: 0}, true},
|
|
{"validate struct passed", &defaultValidator{}, exampleStruct{A: "12345678", B: 1}, false},
|
|
{"validate *struct failed-1", &defaultValidator{}, &exampleStruct{A: "123456789", B: 1}, true},
|
|
{"validate *struct failed-2", &defaultValidator{}, &exampleStruct{A: "12345678", B: 0}, true},
|
|
{"validate *struct passed", &defaultValidator{}, &exampleStruct{A: "12345678", B: 1}, false},
|
|
{"validate []struct failed-1", &defaultValidator{}, []exampleStruct{{A: "123456789", B: 1}}, true},
|
|
{"validate []struct failed-2", &defaultValidator{}, []exampleStruct{{A: "12345678", B: 0}}, true},
|
|
{"validate []struct passed", &defaultValidator{}, []exampleStruct{{A: "12345678", B: 1}}, false},
|
|
{"validate []*struct failed-1", &defaultValidator{}, []*exampleStruct{{A: "123456789", B: 1}}, true},
|
|
{"validate []*struct failed-2", &defaultValidator{}, []*exampleStruct{{A: "12345678", B: 0}}, true},
|
|
{"validate []*struct passed", &defaultValidator{}, []*exampleStruct{{A: "12345678", B: 1}}, false},
|
|
{"validate *[]struct failed-1", &defaultValidator{}, &[]exampleStruct{{A: "123456789", B: 1}}, true},
|
|
{"validate *[]struct failed-2", &defaultValidator{}, &[]exampleStruct{{A: "12345678", B: 0}}, true},
|
|
{"validate *[]struct passed", &defaultValidator{}, &[]exampleStruct{{A: "12345678", B: 1}}, false},
|
|
{"validate *[]*struct failed-1", &defaultValidator{}, &[]*exampleStruct{{A: "123456789", B: 1}}, true},
|
|
{"validate *[]*struct failed-2", &defaultValidator{}, &[]*exampleStruct{{A: "12345678", B: 0}}, true},
|
|
{"validate *[]*struct passed", &defaultValidator{}, &[]*exampleStruct{{A: "12345678", B: 1}}, false},
|
|
{"validate map[string]struct failed-1", &defaultValidator{}, map[string]exampleStruct{"x": {A: "123456789", B: 1}}, true},
|
|
{"validate map[string]struct failed-2", &defaultValidator{}, map[string]exampleStruct{"x": {A: "12345678", B: 0}}, true},
|
|
{"validate map[string]struct passed", &defaultValidator{}, map[string]exampleStruct{"x": {A: "12345678", B: 1}}, false},
|
|
{"validate map[string]*struct failed-1", &defaultValidator{}, map[string]*exampleStruct{"x": {A: "123456789", B: 1}}, true},
|
|
{"validate map[string]*struct failed-2", &defaultValidator{}, map[string]*exampleStruct{"x": {A: "12345678", B: 0}}, true},
|
|
{"validate map[string]*struct passed", &defaultValidator{}, map[string]*exampleStruct{"x": {A: "12345678", B: 1}}, false},
|
|
{"validate *map[string]struct failed-1", &defaultValidator{}, &map[string]exampleStruct{"x": {A: "123456789", B: 1}}, true},
|
|
{"validate *map[string]struct failed-2", &defaultValidator{}, &map[string]exampleStruct{"x": {A: "12345678", B: 0}}, true},
|
|
{"validate *map[string]struct passed", &defaultValidator{}, &map[string]exampleStruct{"x": {A: "12345678", B: 1}}, false},
|
|
{"validate *map[string]*struct failed-1", &defaultValidator{}, &map[string]*exampleStruct{"x": {A: "123456789", B: 1}}, true},
|
|
{"validate *map[string]*struct failed-2", &defaultValidator{}, &map[string]*exampleStruct{"x": {A: "12345678", B: 0}}, true},
|
|
{"validate *map[string]*struct passed", &defaultValidator{}, &map[string]*exampleStruct{"x": {A: "12345678", B: 1}}, false},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if err := tt.v.ValidateStruct(tt.obj); (err != nil) != tt.wantErr {
|
|
t.Errorf("defaultValidator.Validate() error = %v, wantErr %v", err, tt.wantErr)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRegisterValidatorTag(t *testing.T) {
|
|
type CustomSlice []struct {
|
|
A string
|
|
}
|
|
type CustomArray [10]struct {
|
|
A string
|
|
}
|
|
type CustomMap map[string]struct {
|
|
A string
|
|
}
|
|
type CustomStruct struct {
|
|
A string
|
|
}
|
|
type CustomInt int
|
|
|
|
// only slice, array, and map types are accepted
|
|
RegisterValidatorTag("gt=0", CustomSlice{})
|
|
RegisterValidatorTag("gt=0", &CustomSlice{})
|
|
RegisterValidatorTag("gt=0", CustomArray{})
|
|
RegisterValidatorTag("gt=0", &CustomArray{})
|
|
RegisterValidatorTag("gt=0", CustomMap{})
|
|
RegisterValidatorTag("gt=0", &CustomMap{})
|
|
assert.Panics(t, func() { RegisterValidatorTag("gt=0", CustomStruct{}) })
|
|
assert.Panics(t, func() { RegisterValidatorTag("gt=0", &CustomStruct{}) })
|
|
assert.Panics(t, func() { var i CustomInt; RegisterValidatorTag("gt=0", i) })
|
|
assert.Panics(t, func() { var i CustomInt; RegisterValidatorTag("gt=0", &i) })
|
|
}
|
|
|
|
func TestValidatorTagsSlice(t *testing.T) {
|
|
type CustomSlice []struct {
|
|
A string `binding:"max=8"`
|
|
}
|
|
|
|
var (
|
|
invalidSlice = CustomSlice{{"12345678"}}
|
|
invalidVal = CustomSlice{{"123456789"}, {"abcdefgh"}}
|
|
validSlice = CustomSlice{{"12345678"}, {"abcdefgh"}}
|
|
invalidSliceVal = CustomSlice{{"123456789"}}
|
|
)
|
|
|
|
v := &defaultValidator{}
|
|
|
|
// no tags registered for the slice itself yet, so only elements are validated
|
|
assert.NoError(t, v.ValidateStruct(invalidSlice))
|
|
assert.Error(t, v.ValidateStruct(invalidVal))
|
|
assert.NoError(t, v.ValidateStruct(validSlice))
|
|
assert.NoError(t, v.ValidateStruct(&invalidSlice))
|
|
assert.Error(t, v.ValidateStruct(&invalidVal))
|
|
assert.NoError(t, v.ValidateStruct(&validSlice))
|
|
|
|
err := v.ValidateStruct(invalidSliceVal)
|
|
assert.Error(t, err)
|
|
assert.Len(t, err, 1) // only value error
|
|
|
|
RegisterValidatorTag("gt=1", CustomSlice{})
|
|
|
|
assert.Error(t, v.ValidateStruct(invalidSlice))
|
|
assert.Error(t, v.ValidateStruct(invalidVal))
|
|
assert.NoError(t, v.ValidateStruct(validSlice))
|
|
assert.Error(t, v.ValidateStruct(&invalidSlice))
|
|
assert.Error(t, v.ValidateStruct(&invalidVal))
|
|
assert.NoError(t, v.ValidateStruct(&validSlice))
|
|
|
|
err = v.ValidateStruct(invalidSliceVal)
|
|
assert.Error(t, err)
|
|
assert.Len(t, err, 2) // both slice length and value error
|
|
}
|
|
|
|
func TestValidatorTagsMap(t *testing.T) {
|
|
type CustomMap map[string]struct {
|
|
B int `binding:"gt=0"`
|
|
}
|
|
|
|
var (
|
|
invalidMap = CustomMap{"12345678": {1}}
|
|
invalidKey = CustomMap{"123456789": {1}, "abcdefgh": {2}}
|
|
invalidVal = CustomMap{"12345678": {0}, "abcdefgh": {2}}
|
|
invalidMapVal = CustomMap{"12345678": {0}}
|
|
validMap = CustomMap{"12345678": {1}, "abcdefgh": {2}}
|
|
)
|
|
|
|
v := &defaultValidator{}
|
|
|
|
// no tags registered for the map itself yet, so only values are validated
|
|
assert.NoError(t, v.ValidateStruct(invalidMap))
|
|
assert.NoError(t, v.ValidateStruct(invalidKey))
|
|
assert.Error(t, v.ValidateStruct(invalidVal))
|
|
assert.NoError(t, v.ValidateStruct(validMap))
|
|
assert.NoError(t, v.ValidateStruct(&invalidMap))
|
|
assert.NoError(t, v.ValidateStruct(&invalidKey))
|
|
assert.Error(t, v.ValidateStruct(&invalidVal))
|
|
assert.NoError(t, v.ValidateStruct(&validMap))
|
|
|
|
err := v.ValidateStruct(invalidMapVal)
|
|
assert.Error(t, err)
|
|
assert.Len(t, err, 1) // only value error
|
|
|
|
RegisterValidatorTag("gt=1,dive,keys,max=8,endkeys", CustomMap{})
|
|
|
|
assert.Error(t, v.ValidateStruct(invalidMap))
|
|
assert.Error(t, v.ValidateStruct(invalidKey))
|
|
assert.Error(t, v.ValidateStruct(invalidVal))
|
|
assert.NoError(t, v.ValidateStruct(validMap))
|
|
assert.Error(t, v.ValidateStruct(&invalidMap))
|
|
assert.Error(t, v.ValidateStruct(&invalidKey))
|
|
assert.Error(t, v.ValidateStruct(&invalidVal))
|
|
assert.NoError(t, v.ValidateStruct(&validMap))
|
|
|
|
err = v.ValidateStruct(invalidMapVal)
|
|
assert.Error(t, err)
|
|
assert.Len(t, err, 2) // both map size and value errors
|
|
}
|