From a3cb430fa1e43b15e72d7bec5b20d0bdff4c2bb8 Mon Sep 17 00:00:00 2001 From: Dean Karn Date: Mon, 23 Mar 2015 10:57:45 -0400 Subject: [PATCH] issue-#20 add extra param of current struct. --- README.md | 9 ++- baked_in.go | 198 +++++++++++++++++++++++----------------------- doc.go | 8 +- validator.go | 36 +++++---- validator_test.go | 6 +- 5 files changed, 134 insertions(+), 123 deletions(-) diff --git a/README.md b/README.md index 7fa40be..f01a048 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ Package go-validate-yourself ================ -[![Build Status](https://travis-ci.org/joeybloggs/go-validate-yourself.svg?branch=v4-development)](https://travis-ci.org/joeybloggs/go-validate-yourself) +[![Build Status](https://travis-ci.org/joeybloggs/go-validate-yourself.svg?branch=v4)](https://travis-ci.org/joeybloggs/go-validate-yourself) +[![GoDoc](https://godoc.org/gopkg.in/joeybloggs/go-validate-yourself.v4?status.svg)](https://godoc.org/gopkg.in/joeybloggs/go-validate-yourself.v4) Package validator implements value validations for structs and individual fields based on tags. @@ -22,7 +23,7 @@ And then just import the package into your own code. Usage ===== -Please see http://godoc.org/gopkg.in/joeybloggs/go-validate-yourself.v3 for detailed usage docs. +Please see http://godoc.org/gopkg.in/joeybloggs/go-validate-yourself.v4 for detailed usage docs. Contributing ============ @@ -36,3 +37,7 @@ however, there will also be a v2-development brach even though v2 doesn't exist I strongly encourage everyone whom creates a custom validation function to contribute them and help make this package even better. + +License +======= +Distributed under MIT License, please see license file in code for more details. \ No newline at end of file diff --git a/baked_in.go b/baked_in.go index dc4de32..dfab14e 100644 --- a/baked_in.go +++ b/baked_in.go @@ -38,7 +38,7 @@ var BakedInValidators = map[string]ValidationFunc{ "uri": isURI, } -func isURI(val interface{}, field interface{}, param string) bool { +func isURI(top interface{}, current interface{}, field interface{}, param string) bool { st := reflect.ValueOf(field) @@ -53,7 +53,7 @@ func isURI(val interface{}, field interface{}, param string) bool { panic(fmt.Sprintf("Bad field type %T", field)) } -func isURL(val interface{}, field interface{}, param string) bool { +func isURL(top interface{}, current interface{}, field interface{}, param string) bool { st := reflect.ValueOf(field) @@ -76,7 +76,7 @@ func isURL(val interface{}, field interface{}, param string) bool { panic(fmt.Sprintf("Bad field type %T", field)) } -func isEmail(val interface{}, field interface{}, param string) bool { +func isEmail(top interface{}, current interface{}, field interface{}, param string) bool { st := reflect.ValueOf(field) @@ -89,7 +89,7 @@ func isEmail(val interface{}, field interface{}, param string) bool { panic(fmt.Sprintf("Bad field type %T", field)) } -func isHsla(val interface{}, field interface{}, param string) bool { +func isHsla(top interface{}, current interface{}, field interface{}, param string) bool { st := reflect.ValueOf(field) @@ -102,7 +102,7 @@ func isHsla(val interface{}, field interface{}, param string) bool { panic(fmt.Sprintf("Bad field type %T", field)) } -func isHsl(val interface{}, field interface{}, param string) bool { +func isHsl(top interface{}, current interface{}, field interface{}, param string) bool { st := reflect.ValueOf(field) @@ -115,7 +115,7 @@ func isHsl(val interface{}, field interface{}, param string) bool { panic(fmt.Sprintf("Bad field type %T", field)) } -func isRgba(val interface{}, field interface{}, param string) bool { +func isRgba(top interface{}, current interface{}, field interface{}, param string) bool { st := reflect.ValueOf(field) @@ -128,7 +128,7 @@ func isRgba(val interface{}, field interface{}, param string) bool { panic(fmt.Sprintf("Bad field type %T", field)) } -func isRgb(val interface{}, field interface{}, param string) bool { +func isRgb(top interface{}, current interface{}, field interface{}, param string) bool { st := reflect.ValueOf(field) @@ -141,7 +141,7 @@ func isRgb(val interface{}, field interface{}, param string) bool { panic(fmt.Sprintf("Bad field type %T", field)) } -func isHexcolor(val interface{}, field interface{}, param string) bool { +func isHexcolor(top interface{}, current interface{}, field interface{}, param string) bool { st := reflect.ValueOf(field) @@ -154,7 +154,7 @@ func isHexcolor(val interface{}, field interface{}, param string) bool { panic(fmt.Sprintf("Bad field type %T", field)) } -func isHexadecimal(val interface{}, field interface{}, param string) bool { +func isHexadecimal(top interface{}, current interface{}, field interface{}, param string) bool { st := reflect.ValueOf(field) @@ -167,7 +167,7 @@ func isHexadecimal(val interface{}, field interface{}, param string) bool { panic(fmt.Sprintf("Bad field type %T", field)) } -func isNumber(val interface{}, field interface{}, param string) bool { +func isNumber(top interface{}, current interface{}, field interface{}, param string) bool { st := reflect.ValueOf(field) @@ -180,7 +180,7 @@ func isNumber(val interface{}, field interface{}, param string) bool { panic(fmt.Sprintf("Bad field type %T", field)) } -func isNumeric(val interface{}, field interface{}, param string) bool { +func isNumeric(top interface{}, current interface{}, field interface{}, param string) bool { st := reflect.ValueOf(field) @@ -193,7 +193,7 @@ func isNumeric(val interface{}, field interface{}, param string) bool { panic(fmt.Sprintf("Bad field type %T", field)) } -func isAlphanum(val interface{}, field interface{}, param string) bool { +func isAlphanum(top interface{}, current interface{}, field interface{}, param string) bool { st := reflect.ValueOf(field) @@ -206,7 +206,7 @@ func isAlphanum(val interface{}, field interface{}, param string) bool { panic(fmt.Sprintf("Bad field type %T", field)) } -func isAlpha(val interface{}, field interface{}, param string) bool { +func isAlpha(top interface{}, current interface{}, field interface{}, param string) bool { st := reflect.ValueOf(field) @@ -219,7 +219,7 @@ func isAlpha(val interface{}, field interface{}, param string) bool { panic(fmt.Sprintf("Bad field type %T", field)) } -func hasValue(val interface{}, field interface{}, param string) bool { +func hasValue(top interface{}, current interface{}, field interface{}, param string) bool { st := reflect.ValueOf(field) @@ -233,45 +233,45 @@ func hasValue(val interface{}, field interface{}, param string) bool { } } -func isGteField(val interface{}, field interface{}, param string) bool { +func isGteField(top interface{}, current interface{}, field interface{}, param string) bool { - if val == nil { + if current == nil { panic("struct not passed for cross validation") } - topVal := reflect.ValueOf(val) + currentVal := reflect.ValueOf(current) - if topVal.Kind() == reflect.Ptr && !topVal.IsNil() { - topVal = reflect.ValueOf(topVal.Elem().Interface()) + if currentVal.Kind() == reflect.Ptr && !currentVal.IsNil() { + currentVal = reflect.ValueOf(currentVal.Elem().Interface()) } - var topFieldVal reflect.Value + var currentFielVal reflect.Value - switch topVal.Kind() { + switch currentVal.Kind() { case reflect.Struct: - if topVal.Type() == reflect.TypeOf(time.Time{}) { - topFieldVal = topVal + if currentVal.Type() == reflect.TypeOf(time.Time{}) { + currentFielVal = currentVal break } - f := topVal.FieldByName(param) + f := currentVal.FieldByName(param) if f.Kind() == reflect.Invalid { panic(fmt.Sprintf("Field \"%s\" not found in struct", param)) } - topFieldVal = f + currentFielVal = f default: - topFieldVal = topVal + currentFielVal = currentVal } - if topFieldVal.Kind() == reflect.Ptr && !topFieldVal.IsNil() { + if currentFielVal.Kind() == reflect.Ptr && !currentFielVal.IsNil() { - topFieldVal = reflect.ValueOf(topFieldVal.Elem().Interface()) + currentFielVal = reflect.ValueOf(currentFielVal.Elem().Interface()) } fv := reflect.ValueOf(field) @@ -280,25 +280,25 @@ func isGteField(val interface{}, field interface{}, param string) bool { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return fv.Int() >= topFieldVal.Int() + return fv.Int() >= currentFielVal.Int() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return fv.Uint() >= topFieldVal.Uint() + return fv.Uint() >= currentFielVal.Uint() case reflect.Float32, reflect.Float64: - return fv.Float() >= topFieldVal.Float() + return fv.Float() >= currentFielVal.Float() case reflect.Struct: if fv.Type() == reflect.TypeOf(time.Time{}) { - if topFieldVal.Type() != reflect.TypeOf(time.Time{}) { + if currentFielVal.Type() != reflect.TypeOf(time.Time{}) { panic("Bad Top Level field type") } - t := topFieldVal.Interface().(time.Time) + t := currentFielVal.Interface().(time.Time) fieldTime := field.(time.Time) return fieldTime.After(t) || fieldTime.Equal(t) @@ -308,45 +308,45 @@ func isGteField(val interface{}, field interface{}, param string) bool { panic(fmt.Sprintf("Bad field type %T", field)) } -func isGtField(val interface{}, field interface{}, param string) bool { +func isGtField(top interface{}, current interface{}, field interface{}, param string) bool { - if val == nil { + if current == nil { panic("struct not passed for cross validation") } - topVal := reflect.ValueOf(val) + currentVal := reflect.ValueOf(current) - if topVal.Kind() == reflect.Ptr && !topVal.IsNil() { - topVal = reflect.ValueOf(topVal.Elem().Interface()) + if currentVal.Kind() == reflect.Ptr && !currentVal.IsNil() { + currentVal = reflect.ValueOf(currentVal.Elem().Interface()) } - var topFieldVal reflect.Value + var currentFielVal reflect.Value - switch topVal.Kind() { + switch currentVal.Kind() { case reflect.Struct: - if topVal.Type() == reflect.TypeOf(time.Time{}) { - topFieldVal = topVal + if currentVal.Type() == reflect.TypeOf(time.Time{}) { + currentFielVal = currentVal break } - f := topVal.FieldByName(param) + f := currentVal.FieldByName(param) if f.Kind() == reflect.Invalid { panic(fmt.Sprintf("Field \"%s\" not found in struct", param)) } - topFieldVal = f + currentFielVal = f default: - topFieldVal = topVal + currentFielVal = currentVal } - if topFieldVal.Kind() == reflect.Ptr && !topFieldVal.IsNil() { + if currentFielVal.Kind() == reflect.Ptr && !currentFielVal.IsNil() { - topFieldVal = reflect.ValueOf(topFieldVal.Elem().Interface()) + currentFielVal = reflect.ValueOf(currentFielVal.Elem().Interface()) } fv := reflect.ValueOf(field) @@ -355,25 +355,25 @@ func isGtField(val interface{}, field interface{}, param string) bool { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return fv.Int() > topFieldVal.Int() + return fv.Int() > currentFielVal.Int() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return fv.Uint() > topFieldVal.Uint() + return fv.Uint() > currentFielVal.Uint() case reflect.Float32, reflect.Float64: - return fv.Float() > topFieldVal.Float() + return fv.Float() > currentFielVal.Float() case reflect.Struct: if fv.Type() == reflect.TypeOf(time.Time{}) { - if topFieldVal.Type() != reflect.TypeOf(time.Time{}) { + if currentFielVal.Type() != reflect.TypeOf(time.Time{}) { panic("Bad Top Level field type") } - t := topFieldVal.Interface().(time.Time) + t := currentFielVal.Interface().(time.Time) fieldTime := field.(time.Time) return fieldTime.After(t) @@ -383,7 +383,7 @@ func isGtField(val interface{}, field interface{}, param string) bool { panic(fmt.Sprintf("Bad field type %T", field)) } -func isGte(val interface{}, field interface{}, param string) bool { +func isGte(top interface{}, current interface{}, field interface{}, param string) bool { st := reflect.ValueOf(field) @@ -428,7 +428,7 @@ func isGte(val interface{}, field interface{}, param string) bool { panic(fmt.Sprintf("Bad field type %T", field)) } -func isGt(val interface{}, field interface{}, param string) bool { +func isGt(top interface{}, current interface{}, field interface{}, param string) bool { st := reflect.ValueOf(field) @@ -472,7 +472,7 @@ func isGt(val interface{}, field interface{}, param string) bool { // length tests whether a variable's length is equal to a given // value. For strings it tests the number of characters whereas // for maps and slices it tests the number of items. -func hasLengthOf(val interface{}, field interface{}, param string) bool { +func hasLengthOf(top interface{}, current interface{}, field interface{}, param string) bool { st := reflect.ValueOf(field) @@ -511,50 +511,50 @@ func hasLengthOf(val interface{}, field interface{}, param string) bool { // number. For number types, it's a simple lesser-than test; for // strings it tests the number of characters whereas for maps // and slices it tests the number of items. -func hasMinOf(val interface{}, field interface{}, param string) bool { +func hasMinOf(top interface{}, current interface{}, field interface{}, param string) bool { - return isGte(val, field, param) + return isGte(top, current, field, param) } -func isLteField(val interface{}, field interface{}, param string) bool { +func isLteField(top interface{}, current interface{}, field interface{}, param string) bool { - if val == nil { + if current == nil { panic("struct not passed for cross validation") } - topVal := reflect.ValueOf(val) + currentVal := reflect.ValueOf(current) - if topVal.Kind() == reflect.Ptr && !topVal.IsNil() { - topVal = reflect.ValueOf(topVal.Elem().Interface()) + if currentVal.Kind() == reflect.Ptr && !currentVal.IsNil() { + currentVal = reflect.ValueOf(currentVal.Elem().Interface()) } - var topFieldVal reflect.Value + var currentFielVal reflect.Value - switch topVal.Kind() { + switch currentVal.Kind() { case reflect.Struct: - if topVal.Type() == reflect.TypeOf(time.Time{}) { - topFieldVal = topVal + if currentVal.Type() == reflect.TypeOf(time.Time{}) { + currentFielVal = currentVal break } - f := topVal.FieldByName(param) + f := currentVal.FieldByName(param) if f.Kind() == reflect.Invalid { panic(fmt.Sprintf("Field \"%s\" not found in struct", param)) } - topFieldVal = f + currentFielVal = f default: - topFieldVal = topVal + currentFielVal = currentVal } - if topFieldVal.Kind() == reflect.Ptr && !topFieldVal.IsNil() { + if currentFielVal.Kind() == reflect.Ptr && !currentFielVal.IsNil() { - topFieldVal = reflect.ValueOf(topFieldVal.Elem().Interface()) + currentFielVal = reflect.ValueOf(currentFielVal.Elem().Interface()) } fv := reflect.ValueOf(field) @@ -563,25 +563,25 @@ func isLteField(val interface{}, field interface{}, param string) bool { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return fv.Int() <= topFieldVal.Int() + return fv.Int() <= currentFielVal.Int() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return fv.Uint() <= topFieldVal.Uint() + return fv.Uint() <= currentFielVal.Uint() case reflect.Float32, reflect.Float64: - return fv.Float() <= topFieldVal.Float() + return fv.Float() <= currentFielVal.Float() case reflect.Struct: if fv.Type() == reflect.TypeOf(time.Time{}) { - if topFieldVal.Type() != reflect.TypeOf(time.Time{}) { + if currentFielVal.Type() != reflect.TypeOf(time.Time{}) { panic("Bad Top Level field type") } - t := topFieldVal.Interface().(time.Time) + t := currentFielVal.Interface().(time.Time) fieldTime := field.(time.Time) return fieldTime.Before(t) || fieldTime.Equal(t) @@ -591,45 +591,45 @@ func isLteField(val interface{}, field interface{}, param string) bool { panic(fmt.Sprintf("Bad field type %T", field)) } -func isLtField(val interface{}, field interface{}, param string) bool { +func isLtField(top interface{}, current interface{}, field interface{}, param string) bool { - if val == nil { + if current == nil { panic("struct not passed for cross validation") } - topVal := reflect.ValueOf(val) + currentVal := reflect.ValueOf(current) - if topVal.Kind() == reflect.Ptr && !topVal.IsNil() { - topVal = reflect.ValueOf(topVal.Elem().Interface()) + if currentVal.Kind() == reflect.Ptr && !currentVal.IsNil() { + currentVal = reflect.ValueOf(currentVal.Elem().Interface()) } - var topFieldVal reflect.Value + var currentFielVal reflect.Value - switch topVal.Kind() { + switch currentVal.Kind() { case reflect.Struct: - if topVal.Type() == reflect.TypeOf(time.Time{}) { - topFieldVal = topVal + if currentVal.Type() == reflect.TypeOf(time.Time{}) { + currentFielVal = currentVal break } - f := topVal.FieldByName(param) + f := currentVal.FieldByName(param) if f.Kind() == reflect.Invalid { panic(fmt.Sprintf("Field \"%s\" not found in struct", param)) } - topFieldVal = f + currentFielVal = f default: - topFieldVal = topVal + currentFielVal = currentVal } - if topFieldVal.Kind() == reflect.Ptr && !topFieldVal.IsNil() { + if currentFielVal.Kind() == reflect.Ptr && !currentFielVal.IsNil() { - topFieldVal = reflect.ValueOf(topFieldVal.Elem().Interface()) + currentFielVal = reflect.ValueOf(currentFielVal.Elem().Interface()) } fv := reflect.ValueOf(field) @@ -638,25 +638,25 @@ func isLtField(val interface{}, field interface{}, param string) bool { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return fv.Int() < topFieldVal.Int() + return fv.Int() < currentFielVal.Int() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return fv.Uint() < topFieldVal.Uint() + return fv.Uint() < currentFielVal.Uint() case reflect.Float32, reflect.Float64: - return fv.Float() < topFieldVal.Float() + return fv.Float() < currentFielVal.Float() case reflect.Struct: if fv.Type() == reflect.TypeOf(time.Time{}) { - if topFieldVal.Type() != reflect.TypeOf(time.Time{}) { + if currentFielVal.Type() != reflect.TypeOf(time.Time{}) { panic("Bad Top Level field type") } - t := topFieldVal.Interface().(time.Time) + t := currentFielVal.Interface().(time.Time) fieldTime := field.(time.Time) return fieldTime.Before(t) @@ -666,7 +666,7 @@ func isLtField(val interface{}, field interface{}, param string) bool { panic(fmt.Sprintf("Bad field type %T", field)) } -func isLte(val interface{}, field interface{}, param string) bool { +func isLte(top interface{}, current interface{}, field interface{}, param string) bool { st := reflect.ValueOf(field) @@ -711,7 +711,7 @@ func isLte(val interface{}, field interface{}, param string) bool { panic(fmt.Sprintf("Bad field type %T", field)) } -func isLt(val interface{}, field interface{}, param string) bool { +func isLt(top interface{}, current interface{}, field interface{}, param string) bool { st := reflect.ValueOf(field) @@ -757,9 +757,9 @@ func isLt(val interface{}, field interface{}, param string) bool { // value. For numbers, it's a simple lesser-than test; for // strings it tests the number of characters whereas for maps // and slices it tests the number of items. -func hasMaxOf(val interface{}, field interface{}, param string) bool { +func hasMaxOf(top interface{}, current interface{}, field interface{}, param string) bool { - return isLte(val, field, param) + return isLte(top, current, field, param) } // asInt retuns the parameter as a int64 diff --git a/doc.go b/doc.go index e71e0d4..0cbbd11 100644 --- a/doc.go +++ b/doc.go @@ -3,8 +3,6 @@ Package validator implements value validations for structs and individual fields Built In Validator - v3 no longer contains a built in Validator instance. - myValidator = validator.New("validate", validator.BakedInFunctions) errs := myValidator.ValidateStruct(//your struct) @@ -79,7 +77,7 @@ Custom Functions Custom functions can be added //Structure - func customFunc(val interface{}, field interface{}, param string) bool { + func customFunc(top interface{}, current interface{}, field interface{}, param string) bool { if whatever { return false @@ -138,6 +136,10 @@ Bad Validator definitions are not handled by the library Baked In Validators and Tags +NOTE: Baked In Cross field validation only compares fields on the same struct, +if cross field + cross struct validation is needed your own custom validator +should be implemented. + Here is a list of the current built in validators: - diff --git a/validator.go b/validator.go index 5f027ba..b0952c5 100644 --- a/validator.go +++ b/validator.go @@ -101,8 +101,12 @@ func (e *StructValidationErrors) Flatten() map[string]*FieldValidationError { return errs } -// ValidationFunc that accepts a value(optional usage), a field and parameter(optional usage) for use in validation -type ValidationFunc func(val interface{}, v interface{}, param string) bool +// ValidationFunc accepts all values needed for file and cross field validation +// top = top level struct when validating by struct otherwise nil +// current = current level struct when validating by struct otherwise optional comparison value +// f = field value for validation +// param = parameter used in validation i.e. gt=0 param would be 0 +type ValidationFunc func(top interface{}, current interface{}, f interface{}, param string) bool // Validator implements the Validator Struct // NOTE: Fields within are not thread safe and that is on purpose @@ -153,11 +157,11 @@ func (v *Validator) AddFunction(key string, f ValidationFunc) error { // ValidateStruct validates a struct and returns a struct containing the errors func (v *Validator) ValidateStruct(s interface{}) *StructValidationErrors { - return v.validateStructRecursive(s, s) + return v.validateStructRecursive(s, s, s) } // validateStructRecursive validates a struct recursivly and passes the top level struct around for use in validator functions and returns a struct containing the errors -func (v *Validator) validateStructRecursive(top interface{}, s interface{}) *StructValidationErrors { +func (v *Validator) validateStructRecursive(top interface{}, current interface{}, s interface{}) *StructValidationErrors { structValue := reflect.ValueOf(s) structType := reflect.TypeOf(s) @@ -170,7 +174,7 @@ func (v *Validator) validateStructRecursive(top interface{}, s interface{}) *Str } if structValue.Kind() == reflect.Ptr && !structValue.IsNil() { - return v.validateStructRecursive(top, structValue.Elem().Interface()) + return v.validateStructRecursive(top, current, structValue.Elem().Interface()) } if structValue.Kind() != reflect.Struct && structValue.Kind() != reflect.Interface { @@ -209,7 +213,7 @@ func (v *Validator) validateStructRecursive(top interface{}, s interface{}) *Str if valueField.Type() == reflect.TypeOf(time.Time{}) { - if fieldError := v.validateFieldByNameAndTagAndValue(top, valueField.Interface(), typeField.Name, tag); fieldError != nil { + if fieldError := v.validateFieldByNameAndTagAndValue(top, current, valueField.Interface(), typeField.Name, tag); fieldError != nil { validationErrors.Errors[fieldError.Field] = fieldError // free up memory reference fieldError = nil @@ -221,7 +225,7 @@ func (v *Validator) validateStructRecursive(top interface{}, s interface{}) *Str continue } - if structErrors := v.validateStructRecursive(top, valueField.Interface()); structErrors != nil { + if structErrors := v.validateStructRecursive(top, valueField.Interface(), valueField.Interface()); structErrors != nil { validationErrors.StructErrors[typeField.Name] = structErrors // free up memory map no longer needed structErrors = nil @@ -230,7 +234,7 @@ func (v *Validator) validateStructRecursive(top interface{}, s interface{}) *Str default: - if fieldError := v.validateFieldByNameAndTagAndValue(top, valueField.Interface(), typeField.Name, tag); fieldError != nil { + if fieldError := v.validateFieldByNameAndTagAndValue(top, current, valueField.Interface(), typeField.Name, tag); fieldError != nil { validationErrors.Errors[fieldError.Field] = fieldError // free up memory reference fieldError = nil @@ -254,17 +258,17 @@ func (v *Validator) ValidateFieldByTag(f interface{}, tag string) *FieldValidati // ValidateFieldByTagAndValue allows validation of a single field, still using tag style validation to check multiple errors func (v *Validator) ValidateFieldByTagAndValue(val interface{}, f interface{}, tag string) *FieldValidationError { - return v.validateFieldByNameAndTagAndValue(val, f, "", tag) + return v.validateFieldByNameAndTagAndValue(nil, val, f, "", tag) } -func (v *Validator) validateFieldByNameAndTagAndValue(val interface{}, f interface{}, name string, tag string) *FieldValidationError { +func (v *Validator) validateFieldByNameAndTagAndValue(val interface{}, current interface{}, f interface{}, name string, tag string) *FieldValidationError { // This is a double check if coming from ValidateStruct but need to be here in case function is called directly if tag == noValidationTag { return nil } - if strings.Contains(tag, omitempty) && !hasValue(val, f, "") { + if strings.Contains(tag, omitempty) && !hasValue(val, current, f, "") { return nil } @@ -272,7 +276,7 @@ func (v *Validator) validateFieldByNameAndTagAndValue(val interface{}, f interfa fieldKind := valueField.Kind() if fieldKind == reflect.Ptr && !valueField.IsNil() { - return v.validateFieldByNameAndTagAndValue(val, valueField.Elem().Interface(), name, tag) + return v.validateFieldByNameAndTagAndValue(val, current, valueField.Elem().Interface(), name, tag) } fieldType := valueField.Type() @@ -300,7 +304,7 @@ func (v *Validator) validateFieldByNameAndTagAndValue(val interface{}, f interfa for _, val := range orVals { - valErr, err = v.validateFieldByNameAndSingleTag(val, f, name, val) + valErr, err = v.validateFieldByNameAndSingleTag(val, current, f, name, val) if err == nil { return nil @@ -318,7 +322,7 @@ func (v *Validator) validateFieldByNameAndTagAndValue(val interface{}, f interfa return valErr } - if valErr, err = v.validateFieldByNameAndSingleTag(val, f, name, valTag); err != nil { + if valErr, err = v.validateFieldByNameAndSingleTag(val, current, f, name, valTag); err != nil { valErr.Kind = valueField.Kind() valErr.Type = fieldType @@ -330,7 +334,7 @@ func (v *Validator) validateFieldByNameAndTagAndValue(val interface{}, f interfa return nil } -func (v *Validator) validateFieldByNameAndSingleTag(val interface{}, f interface{}, name string, valTag string) (*FieldValidationError, error) { +func (v *Validator) validateFieldByNameAndSingleTag(val interface{}, current interface{}, f interface{}, name string, valTag string) (*FieldValidationError, error) { vals := strings.Split(valTag, tagKeySeparator) key := strings.Trim(vals[0], " ") @@ -361,7 +365,7 @@ func (v *Validator) validateFieldByNameAndSingleTag(val interface{}, f interface param = strings.Trim(vals[1], " ") } - if err := valFunc(val, f, param); !err { + if err := valFunc(val, current, f, param); !err { valErr.Param = param return valErr, errors.New(key) } diff --git a/validator_test.go b/validator_test.go index 1849690..4f66dc0 100644 --- a/validator_test.go +++ b/validator_test.go @@ -127,14 +127,14 @@ func AssertMapFieldError(s map[string]*validator.FieldValidationError, field str c.Assert(val.ErrorTag, Equals, expectedTag) } -func newValidatorFunc(val interface{}, field interface{}, param string) bool { +func newValidatorFunc(val interface{}, current interface{}, field interface{}, param string) bool { return true } -func isEqualFunc(val interface{}, field interface{}, param string) bool { +func isEqualFunc(val interface{}, current interface{}, field interface{}, param string) bool { - return val.(string) == field.(string) + return current.(string) == field.(string) } func (ms *MySuite) TestStructOnlyValidation(c *C) {