Merge pull request #168 from bluesuncorp/v7-development

Update Validator Instance Check
v7 v7.1
Dean Karn 9 years ago
commit 4d7f9e43b1
  1. 2
      README.md
  2. 14
      validator.go
  3. 25
      validator_test.go

@ -227,7 +227,7 @@ please make your pull requests against those branches.
If the changes being proposed or requested are breaking changes, please create an issue, for discussion If the changes being proposed or requested are breaking changes, please create an issue, for discussion
or create a pull request against the highest development branch for example this package has a or create a pull request against the highest development branch for example this package has a
v1 and v1-development branch however, there will also be a v2-development brach even though v2 doesn't exist yet. v1 and v1-development branch however, there will also be a v2-development branch even though v2 doesn't exist yet.
I strongly encourage everyone whom creates a custom validation function to contribute them and I strongly encourage everyone whom creates a custom validation function to contribute them and
help make this package even better. help make this package even better.

@ -35,6 +35,7 @@ const (
mapIndexFieldName = "%s" + leftBracket + "%v" + rightBracket mapIndexFieldName = "%s" + leftBracket + "%v" + rightBracket
invalidValidation = "Invalid validation tag on field %s" invalidValidation = "Invalid validation tag on field %s"
undefinedValidation = "Undefined validation function on field %s" undefinedValidation = "Undefined validation function on field %s"
validatorNotInitialized = "Validator instance not initialized"
) )
var ( var (
@ -78,6 +79,12 @@ type Validate struct {
config Config config Config
} }
func (v *Validate) initCheck() {
if v == nil {
panic(validatorNotInitialized)
}
}
// Config contains the options that a Validator instance will use. // Config contains the options that a Validator instance will use.
// It is passed to the New() function // It is passed to the New() function
type Config struct { type Config struct {
@ -146,6 +153,7 @@ func New(config Config) *Validate {
// NOTE: if the key already exists, the previous validation function will be replaced. // NOTE: if the key already exists, the previous validation function will be replaced.
// NOTE: this method is not thread-safe // NOTE: this method is not thread-safe
func (v *Validate) RegisterValidation(key string, f Func) error { func (v *Validate) RegisterValidation(key string, f Func) error {
v.initCheck()
if len(key) == 0 { if len(key) == 0 {
return errors.New("Function Key cannot be empty") return errors.New("Function Key cannot be empty")
@ -162,6 +170,7 @@ func (v *Validate) RegisterValidation(key string, f Func) error {
// RegisterCustomTypeFunc registers a CustomTypeFunc against a number of types // RegisterCustomTypeFunc registers a CustomTypeFunc against a number of types
func (v *Validate) RegisterCustomTypeFunc(fn CustomTypeFunc, types ...interface{}) { func (v *Validate) RegisterCustomTypeFunc(fn CustomTypeFunc, types ...interface{}) {
v.initCheck()
if v.config.CustomTypeFuncs == nil { if v.config.CustomTypeFuncs == nil {
v.config.CustomTypeFuncs = map[reflect.Type]CustomTypeFunc{} v.config.CustomTypeFuncs = map[reflect.Type]CustomTypeFunc{}
@ -178,6 +187,7 @@ func (v *Validate) RegisterCustomTypeFunc(fn CustomTypeFunc, types ...interface{
// NOTE: it returns ValidationErrors instead of a single FieldError because this can also // NOTE: it returns ValidationErrors instead of a single FieldError because this can also
// validate Array, Slice and maps fields which may contain more than one error // validate Array, Slice and maps fields which may contain more than one error
func (v *Validate) Field(field interface{}, tag string) ValidationErrors { func (v *Validate) Field(field interface{}, tag string) ValidationErrors {
v.initCheck()
errs := errsPool.Get().(ValidationErrors) errs := errsPool.Get().(ValidationErrors)
fieldVal := reflect.ValueOf(field) fieldVal := reflect.ValueOf(field)
@ -196,6 +206,7 @@ func (v *Validate) Field(field interface{}, tag string) ValidationErrors {
// NOTE: it returns ValidationErrors instead of a single FieldError because this can also // NOTE: it returns ValidationErrors instead of a single FieldError because this can also
// validate Array, Slice and maps fields which may contain more than one error // validate Array, Slice and maps fields which may contain more than one error
func (v *Validate) FieldWithValue(val interface{}, field interface{}, tag string) ValidationErrors { func (v *Validate) FieldWithValue(val interface{}, field interface{}, tag string) ValidationErrors {
v.initCheck()
errs := errsPool.Get().(ValidationErrors) errs := errsPool.Get().(ValidationErrors)
topVal := reflect.ValueOf(val) topVal := reflect.ValueOf(val)
@ -216,6 +227,7 @@ func (v *Validate) FieldWithValue(val interface{}, field interface{}, tag string
// NOTE: This is normally not needed, however in some specific cases such as: tied to a // NOTE: This is normally not needed, however in some specific cases such as: tied to a
// legacy data structure, it will be useful // legacy data structure, it will be useful
func (v *Validate) StructPartial(current interface{}, fields ...string) ValidationErrors { func (v *Validate) StructPartial(current interface{}, fields ...string) ValidationErrors {
v.initCheck()
sv, _ := v.extractType(reflect.ValueOf(current)) sv, _ := v.extractType(reflect.ValueOf(current))
name := sv.Type().Name() name := sv.Type().Name()
@ -274,6 +286,7 @@ func (v *Validate) StructPartial(current interface{}, fields ...string) Validati
// NOTE: This is normally not needed, however in some specific cases such as: tied to a // NOTE: This is normally not needed, however in some specific cases such as: tied to a
// legacy data structure, it will be useful // legacy data structure, it will be useful
func (v *Validate) StructExcept(current interface{}, fields ...string) ValidationErrors { func (v *Validate) StructExcept(current interface{}, fields ...string) ValidationErrors {
v.initCheck()
sv, _ := v.extractType(reflect.ValueOf(current)) sv, _ := v.extractType(reflect.ValueOf(current))
name := sv.Type().Name() name := sv.Type().Name()
@ -297,6 +310,7 @@ func (v *Validate) StructExcept(current interface{}, fields ...string) Validatio
// Struct validates a structs exposed fields, and automatically validates nested structs, unless otherwise specified. // Struct validates a structs exposed fields, and automatically validates nested structs, unless otherwise specified.
func (v *Validate) Struct(current interface{}) ValidationErrors { func (v *Validate) Struct(current interface{}) ValidationErrors {
v.initCheck()
errs := errsPool.Get().(ValidationErrors) errs := errsPool.Get().(ValidationErrors)
sv := reflect.ValueOf(current) sv := reflect.ValueOf(current)

@ -210,6 +210,31 @@ type TestPartial struct {
} }
} }
func TestNilValidator(t *testing.T) {
type TestStruct struct {
Test string `validate:"required"`
}
ts := TestStruct{}
var val *Validate
fn := func(v *Validate, topStruct reflect.Value, current reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
return current.String() == field.String()
}
PanicMatches(t, func() { val.RegisterCustomTypeFunc(ValidateCustomType, MadeUpCustomType{}) }, validatorNotInitialized)
PanicMatches(t, func() { val.RegisterValidation("something", fn) }, validatorNotInitialized)
PanicMatches(t, func() { val.Field(ts.Test, "required") }, validatorNotInitialized)
PanicMatches(t, func() { val.FieldWithValue("test", ts.Test, "required") }, validatorNotInitialized)
PanicMatches(t, func() { val.Struct(ts) }, validatorNotInitialized)
PanicMatches(t, func() { val.StructExcept(ts, "Test") }, validatorNotInitialized)
PanicMatches(t, func() { val.StructPartial(ts, "Test") }, validatorNotInitialized)
}
func TestStructPartial(t *testing.T) { func TestStructPartial(t *testing.T) {
p1 := []string{ p1 := []string{

Loading…
Cancel
Save