diff --git a/cmd/prometheus/config_test.go b/cmd/prometheus/config_test.go index a77eaf2072..1b7964721f 100644 --- a/cmd/prometheus/config_test.go +++ b/cmd/prometheus/config_test.go @@ -60,12 +60,17 @@ func TestParse(t *testing.T) { input: []string{"-alertmanager.url", "alertmanager.company.com"}, valid: false, }, + { + input: []string{"-alertmanager.url", "https://double--dash.de"}, + valid: true, + }, } for i, test := range tests { // reset "immutable" config cfg.prometheusURL = "" cfg.influxdbURL = "" + cfg.alertmanagerURLs = stringset{} err := parse(test.input) if test.valid && err != nil { diff --git a/vendor/github.com/asaskevich/govalidator/README.md b/vendor/github.com/asaskevich/govalidator/README.md index 7a083729ee..57d85fd410 100644 --- a/vendor/github.com/asaskevich/govalidator/README.md +++ b/vendor/github.com/asaskevich/govalidator/README.md @@ -1,7 +1,6 @@ govalidator =========== -[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/asaskevich/govalidator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![GoDoc](https://godoc.org/github.com/asaskevich/govalidator?status.png)](https://godoc.org/github.com/asaskevich/govalidator) [![Coverage Status](https://img.shields.io/coveralls/asaskevich/govalidator.svg)](https://coveralls.io/r/asaskevich/govalidator?branch=master) [![views](https://sourcegraph.com/api/repos/github.com/asaskevich/govalidator/.counters/views.png)](https://sourcegraph.com/github.com/asaskevich/govalidator) -[![wercker status](https://app.wercker.com/status/1ec990b09ea86c910d5f08b0e02c6043/s "wercker status")](https://app.wercker.com/project/bykey/1ec990b09ea86c910d5f08b0e02c6043) +[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/asaskevich/govalidator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![GoDoc](https://godoc.org/github.com/asaskevich/govalidator?status.png)](https://godoc.org/github.com/asaskevich/govalidator) [![Coverage Status](https://img.shields.io/coveralls/asaskevich/govalidator.svg)](https://coveralls.io/r/asaskevich/govalidator?branch=master) [![wercker status](https://app.wercker.com/status/1ec990b09ea86c910d5f08b0e02c6043/s "wercker status")](https://app.wercker.com/project/bykey/1ec990b09ea86c910d5f08b0e02c6043) [![Build Status](https://travis-ci.org/asaskevich/govalidator.svg?branch=master)](https://travis-ci.org/asaskevich/govalidator) A package of validators and sanitizers for strings, structs and collections. Based on [validator.js](https://github.com/chriso/validator.js). @@ -12,20 +11,86 @@ Type the following command in your terminal: go get github.com/asaskevich/govalidator +or you can get specified release of the package with `gopkg.in`: + + go get gopkg.in/asaskevich/govalidator.v4 + After it the package is ready to use. + #### Import package in your project Add following line in your `*.go` file: ```go import "github.com/asaskevich/govalidator" ``` -If you unhappy to use long `govalidator`, you can do something like this: +If you are unhappy to use long `govalidator`, you can do something like this: ```go import ( - valid "github.com/asaskevich/govalidator" + valid "github.com/asaskevich/govalidator" ) ``` +#### Activate behavior to require all fields have a validation tag by default +`SetFieldsRequiredByDefault` causes validation to fail when struct fields do not include validations or are not explicitly marked as exempt (using `valid:"-"` or `valid:"email,optional"`). A good place to activate this is a package init function or the main() function. + +```go +import "github.com/asaskevich/govalidator" + +func init() { + govalidator.SetFieldsRequiredByDefault(true) +} +``` + +Here's some code to explain it: +```go +// this struct definition will fail govalidator.ValidateStruct() (and the field values do not matter): +type exampleStruct struct { + Name string `` + Email string `valid:"email"` +} + +// this, however, will only fail when Email is empty or an invalid email address: +type exampleStruct2 struct { + Name string `valid:"-"` + Email string `valid:"email"` +} + +// lastly, this will only fail when Email is an invalid email address but not when it's empty: +type exampleStruct2 struct { + Name string `valid:"-"` + Email string `valid:"email,optional"` +} +``` + +#### Recent breaking changes (see [#123](https://github.com/asaskevich/govalidator/pull/123)) +##### Custom validator function signature +A context was added as the second parameter, for structs this is the object being validated – this makes dependent validation possible. +```go +import "github.com/asaskevich/govalidator" + +// old signature +func(i interface{}) bool + +// new signature +func(i interface{}, o interface{}) bool +``` + +##### Adding a custom validator +This was changed to prevent data races when accessing custom validators. +```go +import "github.com/asaskevich/govalidator" + +// before +govalidator.CustomTypeTagMap["customByteArrayValidator"] = CustomTypeValidator(func(i interface{}, o interface{}) bool { + // ... +}) + +// after +govalidator.CustomTypeTagMap.Set("customByteArrayValidator", CustomTypeValidator(func(i interface{}, o interface{}) bool { + // ... +})) +``` + #### List of functions: ```go func Abs(value float64) float64 @@ -184,6 +249,8 @@ govalidator.TagMap["duck"] = govalidator.Validator(func(str string) bool { return str == "duck" }) ``` +For completely custom validators (interface-based), see below. + Here is a list of available validators for struct fields (validator - used function): ```go "alpha": IsAlpha, @@ -272,6 +339,49 @@ println(result) println(govalidator.WhiteList("a3a43a5a4a3a2a23a4a5a4a3a4", "a-z") == "aaaaaaaaaaaa") ``` +###### Custom validation functions +Custom validation using your own domain specific validators is also available - here's an example of how to use it: +```go +import "github.com/asaskevich/govalidator" + +type CustomByteArray [6]byte // custom types are supported and can be validated + +type StructWithCustomByteArray struct { + ID CustomByteArray `valid:"customByteArrayValidator,customMinLengthValidator"` // multiple custom validators are possible as well and will be evaluated in sequence + Email string `valid:"email"` + CustomMinLength int `valid:"-"` +} + +govalidator.CustomTypeTagMap.Set("customByteArrayValidator", CustomTypeValidator(func(i interface{}, context interface{}) bool { + switch v := context.(type) { // you can type switch on the context interface being validated + case StructWithCustomByteArray: + // you can check and validate against some other field in the context, + // return early or not validate against the context at all – your choice + case SomeOtherType: + // ... + default: + // expecting some other type? Throw/panic here or continue + } + + switch v := i.(type) { // type switch on the struct field being validated + case CustomByteArray: + for _, e := range v { // this validator checks that the byte array is not empty, i.e. not all zeroes + if e != 0 { + return true + } + } + } + return false +})) +govalidator.CustomTypeTagMap.Set("customMinLengthValidator", CustomTypeValidator(func(i interface{}, context interface{}) bool { + switch v := context.(type) { // this validates a field against the value in another field, i.e. dependent validation + case StructWithCustomByteArray: + return len(v.ID) >= v.CustomMinLength + } + return false +})) +``` + #### Notes Documentation is available here: [godoc.org](https://godoc.org/github.com/asaskevich/govalidator). Full information about code coverage is also available here: [govalidator on gocover.io](http://gocover.io/github.com/asaskevich/govalidator). @@ -280,6 +390,7 @@ Full information about code coverage is also available here: [govalidator on goc If you do have a contribution for the package feel free to put up a Pull Request or open Issue. #### Special thanks to [contributors](https://github.com/asaskevich/govalidator/graphs/contributors) +* [Daniel Lohse](https://github.com/annismckenzie) * [Attila Oláh](https://github.com/attilaolah) * [Daniel Korner](https://github.com/Dadie) * [Steven Wilkin](https://github.com/stevenwilkin) @@ -288,5 +399,3 @@ If you do have a contribution for the package feel free to put up a Pull Request * [Nathan Davies](https://github.com/nathj07) * [Matt Sanford](https://github.com/mzsanford) * [Simon ccl1115](https://github.com/ccl1115) - -[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/asaskevich/govalidator/trend.png)](https://bitdeli.com/free "Bitdeli Badge") diff --git a/vendor/github.com/asaskevich/govalidator/arrays.go b/vendor/github.com/asaskevich/govalidator/arrays.go index 55b8aacd8e..5bace2654d 100644 --- a/vendor/github.com/asaskevich/govalidator/arrays.go +++ b/vendor/github.com/asaskevich/govalidator/arrays.go @@ -18,7 +18,7 @@ func Each(array []interface{}, iterator Iterator) { // Map iterates over the slice and apply ResultIterator to every item. Returns new slice as a result. func Map(array []interface{}, iterator ResultIterator) []interface{} { - var result []interface{} = make([]interface{}, len(array)) + var result = make([]interface{}, len(array)) for index, data := range array { result[index] = iterator(data, index) } @@ -37,7 +37,7 @@ func Find(array []interface{}, iterator ConditionIterator) interface{} { // Filter iterates over the slice and apply ConditionIterator to every item. Returns new slice. func Filter(array []interface{}, iterator ConditionIterator) []interface{} { - var result []interface{} = make([]interface{}, 0) + var result = make([]interface{}, 0) for index, data := range array { if iterator(data, index) { result = append(result, data) diff --git a/vendor/github.com/asaskevich/govalidator/error.go b/vendor/github.com/asaskevich/govalidator/error.go index 55d5fca0f1..280b1c455d 100644 --- a/vendor/github.com/asaskevich/govalidator/error.go +++ b/vendor/github.com/asaskevich/govalidator/error.go @@ -1,7 +1,9 @@ package govalidator +// Errors is an array of multiple errors and conforms to the error interface. type Errors []error +// Errors returns itself. func (es Errors) Errors() []error { return es } @@ -14,6 +16,7 @@ func (es Errors) Error() string { return err } +// Error encapsulates a name, an error and whether there's a custom error message or not. type Error struct { Name string Err error @@ -23,7 +26,6 @@ type Error struct { func (e Error) Error() string { if e.CustomErrorMessageExists { return e.Err.Error() - } else { - return e.Name + ": " + e.Err.Error() } + return e.Name + ": " + e.Err.Error() } diff --git a/vendor/github.com/asaskevich/govalidator/patterns.go b/vendor/github.com/asaskevich/govalidator/patterns.go index 42389bda02..8761224cd3 100644 --- a/vendor/github.com/asaskevich/govalidator/patterns.go +++ b/vendor/github.com/asaskevich/govalidator/patterns.go @@ -30,7 +30,7 @@ const ( Latitude string = "^[-+]?([1-8]?\\d(\\.\\d+)?|90(\\.0+)?)$" Longitude string = "^[-+]?(180(\\.0+)?|((1[0-7]\\d)|([1-9]?\\d))(\\.\\d+)?)$" DNSName string = `^([a-zA-Z0-9]{1}[a-zA-Z0-9_-]{1,62}){1}(\.[a-zA-Z0-9]{1}[a-zA-Z0-9_-]{1,62})*$` - URL string = `^((ftp|https?):\/\/)?(\S+(:\S*)?@)?((([1-9]\d?|1\d\d|2[01]\d|22[0-3])(\.(1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(([a-zA-Z0-9]+([-\.][a-zA-Z0-9]+)*)|((www\.)?))?(([a-zA-Z\x{00a1}-\x{ffff}0-9]+-?-?)*[a-zA-Z\x{00a1}-\x{ffff}0-9]+)(?:\.([a-zA-Z\x{00a1}-\x{ffff}]{1,}))?))(:(\d{1,5}))?((\/|\?|#)[^\s]*)?$` + URL string = `^((ftp|https?):\/\/)?(\S+(:\S*)?@)?((([1-9]\d?|1\d\d|2[01]\d|22[0-3])(\.(1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(([a-zA-Z0-9]([a-zA-Z0-9-]+)?[a-zA-Z0-9]([-\.][a-zA-Z0-9]+)*)|((www\.)?))?(([a-zA-Z\x{00a1}-\x{ffff}0-9]+-?-?)*[a-zA-Z\x{00a1}-\x{ffff}0-9]+)(?:\.([a-zA-Z\x{00a1}-\x{ffff}]{1,}))?))(:(\d{1,5}))?((\/|\?|#)[^\s]*)?$` SSN string = `^\d{3}[- ]?\d{2}[- ]?\d{4}$` WinPath string = `^[a-zA-Z]:\\(?:[^\\/:*?"<>|\r\n]+\\)*[^\\/:*?"<>|\r\n]*$` UnixPath string = `^((?:\/[a-zA-Z0-9\.\:]+(?:_[a-zA-Z0-9\:\.]+)*(?:\-[\:a-zA-Z0-9\.]+)*)+\/?)$` diff --git a/vendor/github.com/asaskevich/govalidator/types.go b/vendor/github.com/asaskevich/govalidator/types.go index abbe3d10ba..b715612762 100644 --- a/vendor/github.com/asaskevich/govalidator/types.go +++ b/vendor/github.com/asaskevich/govalidator/types.go @@ -3,17 +3,19 @@ package govalidator import ( "reflect" "regexp" + "sync" ) // Validator is a wrapper for a validator function that returns bool and accepts string. type Validator func(str string) bool // CustomTypeValidator is a wrapper for validator functions that returns bool and accepts any type. -type CustomTypeValidator func(i interface{}) bool +// The second parameter should be the context (in the case of validating a struct: the whole object being validated). +type CustomTypeValidator func(i interface{}, o interface{}) bool // ParamValidator is a wrapper for validator functions that accepts additional parameters. type ParamValidator func(str string, params ...string) bool -type tagOptions []string +type tagOptionsMap map[string]string // UnsupportedTypeError is a wrapper for reflect.Type type UnsupportedTypeError struct { @@ -31,16 +33,36 @@ var ParamTagMap = map[string]ParamValidator{ "matches": StringMatches, } +// ParamTagRegexMap maps param tags to their respective regexes. var ParamTagRegexMap = map[string]*regexp.Regexp{ "length": regexp.MustCompile("^length\\((\\d+)\\|(\\d+)\\)$"), "stringlength": regexp.MustCompile("^stringlength\\((\\d+)\\|(\\d+)\\)$"), "matches": regexp.MustCompile(`matches\(([^)]+)\)`), } +type customTypeTagMap struct { + validators map[string]CustomTypeValidator + + sync.RWMutex +} + +func (tm *customTypeTagMap) Get(name string) (CustomTypeValidator, bool) { + tm.RLock() + defer tm.RUnlock() + v, ok := tm.validators[name] + return v, ok +} + +func (tm *customTypeTagMap) Set(name string, ctv CustomTypeValidator) { + tm.Lock() + defer tm.Unlock() + tm.validators[name] = ctv +} + // CustomTypeTagMap is a map of functions that can be used as tags for ValidateStruct function. // Use this to validate compound or custom types that need to be handled as a whole, e.g. // `type UUID [16]byte` (this would be handled as an array of bytes). -var CustomTypeTagMap = map[string]CustomTypeValidator{} +var CustomTypeTagMap = &customTypeTagMap{validators: make(map[string]CustomTypeValidator)} // TagMap is a map of functions, that can be used as tags for ValidateStruct function. var TagMap = map[string]Validator{ diff --git a/vendor/github.com/asaskevich/govalidator/utils.go b/vendor/github.com/asaskevich/govalidator/utils.go index 0eff62f21c..200b9131de 100644 --- a/vendor/github.com/asaskevich/govalidator/utils.go +++ b/vendor/github.com/asaskevich/govalidator/utils.go @@ -189,7 +189,7 @@ func NormalizeEmail(str string) (string, error) { return strings.Join(parts, "@"), nil } -// Will truncate a string closest length without breaking words. +// Truncate a string to the closest length without breaking words. func Truncate(str string, length int, ending string) string { var aftstr, befstr string if len(str) > length { @@ -203,9 +203,8 @@ func Truncate(str string, length int, ending string) string { if present > length && i != 0 { if (length - before) < (present - length) { return Trim(befstr, " /\\.,\"'#!?&@+-") + ending - } else { - return Trim(aftstr, " /\\.,\"'#!?&@+-") + ending } + return Trim(aftstr, " /\\.,\"'#!?&@+-") + ending } } } diff --git a/vendor/github.com/asaskevich/govalidator/validator.go b/vendor/github.com/asaskevich/govalidator/validator.go index 70422c0696..a752624fc3 100644 --- a/vendor/github.com/asaskevich/govalidator/validator.go +++ b/vendor/github.com/asaskevich/govalidator/validator.go @@ -529,7 +529,8 @@ func IsLongitude(str string) bool { return rxLongitude.MatchString(str) } -// ValidateStruct use tags for fields +// ValidateStruct use tags for fields. +// result will be equal to `false` if there are any errors. func ValidateStruct(s interface{}) (bool, error) { if s == nil { return true, nil @@ -551,9 +552,9 @@ func ValidateStruct(s interface{}) (bool, error) { if typeField.PkgPath != "" { continue // Private field } - resultField, err := typeCheck(valueField, typeField) - if err != nil { - errs = append(errs, err) + resultField, err2 := typeCheck(valueField, typeField, val) + if err2 != nil { + errs = append(errs, err2) } result = result && resultField } @@ -563,11 +564,22 @@ func ValidateStruct(s interface{}) (bool, error) { return result, err } -// parseTag splits a struct field's tag into its -// comma-separated options. -func parseTag(tag string) tagOptions { - split := strings.SplitN(tag, ",", -1) - return tagOptions(split) +// parseTagIntoMap parses a struct tag `valid:required~Some error message,length(2|3)` into map[string]string{"required": "Some error message", "length(2|3)": ""} +func parseTagIntoMap(tag string) tagOptionsMap { + optionsMap := make(tagOptionsMap) + options := strings.SplitN(tag, ",", -1) + for _, option := range options { + validationOptions := strings.Split(option, "~") + if !isValidTag(validationOptions[0]) { + continue + } + if len(validationOptions) == 2 { + optionsMap[validationOptions[0]] = validationOptions[1] + } else { + optionsMap[validationOptions[0]] = "" + } + } + return optionsMap } func isValidTag(s string) bool { @@ -635,52 +647,20 @@ func StringLength(str string, params ...string) bool { return false } -// Contains returns whether checks that a comma-separated list of options -// contains a particular substr flag. substr must be surrounded by a -// string boundary or commas. -func (opts tagOptions) contains(optionName string) bool { - for i := range opts { - tagOpt := opts[i] - if tagOpt == optionName { - return true +func checkRequired(v reflect.Value, t reflect.StructField, options tagOptionsMap) (bool, error) { + if requiredOption, isRequired := options["required"]; isRequired { + if len(requiredOption) > 0 { + return false, Error{t.Name, fmt.Errorf(requiredOption), true} } - } - return false -} - -func searchOption(limit int, predicate func(counter int) bool) int { - for counter := 0; counter < limit; counter++ { - if predicate(counter) { - return counter - } - } - return -1 -} - -func checkRequired(v reflect.Value, t reflect.StructField, options tagOptions) (bool, error) { - var err error - var customErrorMessageExists bool - requiredIndex := searchOption(len(options), func(index int) bool { return strings.HasPrefix(options[index], "required") }) - optionalIndex := searchOption(len(options), func(index int) bool { return strings.HasPrefix(options[index], "optional") }) - if requiredIndex > -1 { - validationOptions := strings.Split(options[requiredIndex], "~") - if len(validationOptions) == 2 { - err = fmt.Errorf(strings.Split(options[requiredIndex], "~")[1]) - customErrorMessageExists = true - } else { - err = fmt.Errorf("non zero value required") - } - return false, Error{t.Name, err, customErrorMessageExists} - } else if fieldsRequiredByDefault && optionalIndex == -1 { - err := fmt.Errorf("All fields are required to at least have one validation defined") - return false, Error{t.Name, err, customErrorMessageExists} + return false, Error{t.Name, fmt.Errorf("non zero value required"), false} + } else if _, isOptional := options["optional"]; fieldsRequiredByDefault && !isOptional { + return false, Error{t.Name, fmt.Errorf("All fields are required to at least have one validation defined"), false} } // not required and empty is valid return true, nil } -func typeCheck(v reflect.Value, t reflect.StructField) (bool, error) { - var customErrorMessageExists bool +func typeCheck(v reflect.Value, t reflect.StructField, o reflect.Value) (bool, error) { if !v.IsValid() { return false, nil } @@ -693,30 +673,32 @@ func typeCheck(v reflect.Value, t reflect.StructField) (bool, error) { if !fieldsRequiredByDefault { return true, nil } - err := fmt.Errorf("All fields are required to at least have one validation defined") - return false, Error{t.Name, err, customErrorMessageExists} + return false, Error{t.Name, fmt.Errorf("All fields are required to at least have one validation defined"), false} case "-": return true, nil } - options := parseTag(tag) - for i := range options { - tagOpt := options[i] - tagOptions := strings.Split(tagOpt, "~") - if ok := isValidTag(tagOptions[0]); !ok { - continue - } - if validatefunc, ok := CustomTypeTagMap[tagOptions[0]]; ok { - options = append(options[:i], options[i+1:]...) // we found our custom validator, so remove it from the options - if result := validatefunc(v.Interface()); !result { - if len(tagOptions) == 2 { - return false, Error{t.Name, fmt.Errorf(tagOptions[1]), true} + options := parseTagIntoMap(tag) + var customTypeErrors Errors + var customTypeValidatorsExist bool + for validatorName, customErrorMessage := range options { + if validatefunc, ok := CustomTypeTagMap.Get(validatorName); ok { + customTypeValidatorsExist = true + if result := validatefunc(v.Interface(), o.Interface()); !result { + if len(customErrorMessage) > 0 { + customTypeErrors = append(customTypeErrors, Error{Name: t.Name, Err: fmt.Errorf(customErrorMessage), CustomErrorMessageExists: true}) + continue } - return false, Error{t.Name, fmt.Errorf("%s does not validate as %s", fmt.Sprint(v), tagOptions[0]), false} + customTypeErrors = append(customTypeErrors, Error{Name: t.Name, Err: fmt.Errorf("%s does not validate as %s", fmt.Sprint(v), validatorName), CustomErrorMessageExists: false}) } - return true, nil } } + if customTypeValidatorsExist { + if len(customTypeErrors.Errors()) > 0 { + return false, customTypeErrors + } + return true, nil + } if isEmptyValue(v) { // an empty value is not validated, check only required @@ -730,25 +712,18 @@ func typeCheck(v reflect.Value, t reflect.StructField) (bool, error) { reflect.Float32, reflect.Float64, reflect.String: // for each tag option check the map of validator functions - for i := range options { - tagOpt := options[i] - tagOptions := strings.Split(tagOpt, "~") - negate := false - customMsgExists := (len(tagOptions) == 2) + for validator, customErrorMessage := range options { + var negate bool + customMsgExists := (len(customErrorMessage) > 0) // Check wether the tag looks like '!something' or 'something' - if len(tagOptions[0]) > 0 && tagOptions[0][0] == '!' { - tagOpt = string(tagOptions[0][1:]) - tagOptions[0] = tagOpt + if validator[0] == '!' { + validator = string(validator[1:]) negate = true } - if ok := isValidTag(tagOptions[0]); !ok { - err := fmt.Errorf("Unknown Validator %s", tagOptions[0]) - return false, Error{t.Name, err, false} - } // Check for param validators for key, value := range ParamTagRegexMap { - ps := value.FindStringSubmatch(tagOptions[0]) + ps := value.FindStringSubmatch(validator) if len(ps) > 0 { if validatefunc, ok := ParamTagMap[key]; ok { switch v.Kind() { @@ -758,30 +733,29 @@ func typeCheck(v reflect.Value, t reflect.StructField) (bool, error) { var err error if !negate { if customMsgExists { - err = fmt.Errorf(tagOptions[1]) + err = fmt.Errorf(customErrorMessage) } else { - err = fmt.Errorf("%s does not validate as %s", field, tagOpt) + err = fmt.Errorf("%s does not validate as %s", field, validator) } } else { if customMsgExists { - err = fmt.Errorf(tagOptions[1]) + err = fmt.Errorf(customErrorMessage) } else { - err = fmt.Errorf("%s does validate as %s", field, tagOpt) + err = fmt.Errorf("%s does validate as %s", field, validator) } } return false, Error{t.Name, err, customMsgExists} } default: - //Not Yet Supported Types (Fail here!) - err := fmt.Errorf("Validator %s doesn't support kind %s", tagOptions[0], v.Kind()) - return false, Error{t.Name, err, false} + // type not yet supported, fail + return false, Error{t.Name, fmt.Errorf("Validator %s doesn't support kind %s", validator, v.Kind()), false} } } } } - if validatefunc, ok := TagMap[tagOptions[0]]; ok { + if validatefunc, ok := TagMap[validator]; ok { switch v.Kind() { case reflect.String: field := fmt.Sprint(v) // make value into string, then validate with regex @@ -790,22 +764,22 @@ func typeCheck(v reflect.Value, t reflect.StructField) (bool, error) { if !negate { if customMsgExists { - err = fmt.Errorf(tagOptions[1]) + err = fmt.Errorf(customErrorMessage) } else { - err = fmt.Errorf("%s does not validate as %s", field, tagOpt) + err = fmt.Errorf("%s does not validate as %s", field, validator) } } else { if customMsgExists { - err = fmt.Errorf(tagOptions[1]) + err = fmt.Errorf(customErrorMessage) } else { - err = fmt.Errorf("%s does validate as %s", field, tagOpt) + err = fmt.Errorf("%s does validate as %s", field, validator) } } return false, Error{t.Name, err, customMsgExists} } default: //Not Yet Supported Types (Fail here!) - err := fmt.Errorf("Validator %s doesn't support kind %s for value %v", tagOptions[0], v.Kind(), v) + err := fmt.Errorf("Validator %s doesn't support kind %s for value %v", validator, v.Kind(), v) return false, Error{t.Name, err, false} } } @@ -833,7 +807,7 @@ func typeCheck(v reflect.Value, t reflect.StructField) (bool, error) { var resultItem bool var err error if v.Index(i).Kind() != reflect.Struct { - resultItem, err = typeCheck(v.Index(i), t) + resultItem, err = typeCheck(v.Index(i), t, o) if err != nil { return false, err } @@ -852,7 +826,7 @@ func typeCheck(v reflect.Value, t reflect.StructField) (bool, error) { var resultItem bool var err error if v.Index(i).Kind() != reflect.Struct { - resultItem, err = typeCheck(v.Index(i), t) + resultItem, err = typeCheck(v.Index(i), t, o) if err != nil { return false, err } @@ -876,7 +850,7 @@ func typeCheck(v reflect.Value, t reflect.StructField) (bool, error) { if v.IsNil() { return true, nil } - return typeCheck(v.Elem(), t) + return typeCheck(v.Elem(), t, o) case reflect.Struct: return ValidateStruct(v.Interface()) default: @@ -929,7 +903,10 @@ func ErrorsByField(e error) map[string]string { m[e.(Error).Name] = e.(Error).Err.Error() case Errors: for _, item := range e.(Errors).Errors() { - m[item.(Error).Name] = item.(Error).Err.Error() + n := ErrorsByField(item) + for k, v := range n { + m[k] = v + } } } diff --git a/vendor/vendor.json b/vendor/vendor.json index d8c51dcd73..e983daae3f 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -3,10 +3,10 @@ "ignore": "test appengine", "package": [ { - "checksumSHA1": "DypC2gHBVRhfPqBbsuGYgkrjvOw=", + "checksumSHA1": "CDOphCxF7dup+hBBVRpFeQhM9Jw=", "path": "github.com/asaskevich/govalidator", - "revision": "5b6e9375cbf581a9008064f7216e816b568d6daa", - "revisionTime": "2016-04-23T17:31:43Z" + "revision": "593d64559f7600f29581a3ee42177f5dbded27a9", + "revisionTime": "2016-07-15T17:06:12Z" }, { "checksumSHA1": "gzORxKc4oYt8ROSTT0UnuczfJB0=",