diff --git a/README.md b/README.md index 7583259..4f52d21 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ Package validator ================ - + [![Join the chat at https://gitter.im/bluesuncorp/validator](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-playground/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -![Project status](https://img.shields.io/badge/version-8.18.1-green.svg) +![Project status](https://img.shields.io/badge/alpha-9.0.0-red.svg) [![Build Status](https://semaphoreci.com/api/v1/projects/ec20115f-ef1b-4c7d-9393-cc76aba74eb4/530054/badge.svg)](https://semaphoreci.com/joeybloggs/validator) -[![Coverage Status](https://coveralls.io/repos/go-playground/validator/badge.svg?branch=v8&service=github)](https://coveralls.io/github/go-playground/validator?branch=v8) +[![Coverage Status](https://coveralls.io/repos/go-playground/validator/badge.svg?branch=v9&service=github)](https://coveralls.io/github/go-playground/validator?branch=v9) [![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/validator)](https://goreportcard.com/report/github.com/go-playground/validator) -[![GoDoc](https://godoc.org/gopkg.in/go-playground/validator.v8?status.svg)](https://godoc.org/gopkg.in/go-playground/validator.v8) +[![GoDoc](https://godoc.org/gopkg.in/go-playground/validator.v9?status.svg)](https://godoc.org/gopkg.in/go-playground/validator.v8) ![License](https://img.shields.io/dub/l/vibe-d.svg) Package validator implements value validations for structs and individual fields based on tags. @@ -25,15 +25,15 @@ Installation Use go get. - go get gopkg.in/go-playground/validator.v8 + go get gopkg.in/go-playground/validator.v9 or to update - go get -u gopkg.in/go-playground/validator.v8 + go get -u gopkg.in/go-playground/validator.v9 Then import the validator package into your own code. - import "gopkg.in/go-playground/validator.v8" + import "gopkg.in/go-playground/validator.v9" Error Return Value ------- @@ -57,7 +57,7 @@ validationErrors := err.(validator.ValidationErrors) Usage and documentation ------ -Please see http://godoc.org/gopkg.in/go-playground/validator.v8 for detailed usage docs. +Please see http://godoc.org/gopkg.in/go-playground/validator.v9 for detailed usage docs. ##### Examples: @@ -68,7 +68,7 @@ package main import ( "fmt" - "gopkg.in/go-playground/validator.v8" + "gopkg.in/go-playground/validator.v9" ) // User contains user information @@ -211,7 +211,7 @@ import ( "fmt" "reflect" - "gopkg.in/go-playground/validator.v8" + "gopkg.in/go-playground/validator.v9" ) // User contains user information @@ -346,21 +346,13 @@ Complimentary Software Here is a list of software that compliments using this library either pre or post validation. -* [Gorilla Schema](https://github.com/gorilla/schema) - Package gorilla/schema fills a struct with form values. +* [form](https://github.com/go-playground/form) - Decodes url.Values into Go value(s) and Encodes Go value(s) into url.Values. Dual Array and Full map support. * [Conform](https://github.com/leebenson/conform) - Trims, sanitizes & scrubs data based on struct tags. How to Contribute ------ -There will always be a development branch for each version i.e. `v1-development`. In order to contribute, -please make your pull requests against those branches. - -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 -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 -help make this package even better. +Make a pull request... License ------ diff --git a/baked_in.go b/baked_in.go index 44aaa08..f5dee2a 100644 --- a/baked_in.go +++ b/baked_in.go @@ -10,156 +10,171 @@ import ( "unicode/utf8" ) -// BakedInAliasValidators is a default mapping of a single validationstag that -// defines a common or complex set of validation(s) to simplify -// adding validation to structs. i.e. set key "_ageok" and the tags -// are "gt=0,lte=130" or key "_preferredname" and tags "omitempty,gt=0,lte=60" -var bakedInAliasValidators = map[string]string{ - "iscolor": "hexcolor|rgb|rgba|hsl|hsla", -} - -// BakedInValidators is the default map of ValidationFunc -// you can add, remove or even replace items to suite your needs, -// or even disregard and use your own map if so desired. -var bakedInValidators = map[string]Func{ - "required": HasValue, - "len": HasLengthOf, - "min": HasMinOf, - "max": HasMaxOf, - "eq": IsEq, - "ne": IsNe, - "lt": IsLt, - "lte": IsLte, - "gt": IsGt, - "gte": IsGte, - "eqfield": IsEqField, - "eqcsfield": IsEqCrossStructField, - "necsfield": IsNeCrossStructField, - "gtcsfield": IsGtCrossStructField, - "gtecsfield": IsGteCrossStructField, - "ltcsfield": IsLtCrossStructField, - "ltecsfield": IsLteCrossStructField, - "nefield": IsNeField, - "gtefield": IsGteField, - "gtfield": IsGtField, - "ltefield": IsLteField, - "ltfield": IsLtField, - "alpha": IsAlpha, - "alphanum": IsAlphanum, - "numeric": IsNumeric, - "number": IsNumber, - "hexadecimal": IsHexadecimal, - "hexcolor": IsHEXColor, - "rgb": IsRGB, - "rgba": IsRGBA, - "hsl": IsHSL, - "hsla": IsHSLA, - "email": IsEmail, - "url": IsURL, - "uri": IsURI, - "base64": IsBase64, - "contains": Contains, - "containsany": ContainsAny, - "containsrune": ContainsRune, - "excludes": Excludes, - "excludesall": ExcludesAll, - "excludesrune": ExcludesRune, - "isbn": IsISBN, - "isbn10": IsISBN10, - "isbn13": IsISBN13, - "uuid": IsUUID, - "uuid3": IsUUID3, - "uuid4": IsUUID4, - "uuid5": IsUUID5, - "ascii": IsASCII, - "printascii": IsPrintableASCII, - "multibyte": HasMultiByteCharacter, - "datauri": IsDataURI, - "latitude": IsLatitude, - "longitude": IsLongitude, - "ssn": IsSSN, - "ipv4": IsIPv4, - "ipv6": IsIPv6, - "ip": IsIP, - "cidrv4": IsCIDRv4, - "cidrv6": IsCIDRv6, - "cidr": IsCIDR, - "tcp4_addr": IsTCP4AddrResolvable, - "tcp6_addr": IsTCP6AddrResolvable, - "tcp_addr": IsTCPAddrResolvable, - "udp4_addr": IsUDP4AddrResolvable, - "udp6_addr": IsUDP6AddrResolvable, - "udp_addr": IsUDPAddrResolvable, - "ip4_addr": IsIP4AddrResolvable, - "ip6_addr": IsIP6AddrResolvable, - "ip_addr": IsIPAddrResolvable, - "unix_addr": IsUnixAddrResolvable, - "mac": IsMAC, -} +// Func accepts all values needed for file and cross field validation +// fl = FieldLevel validation helper +// field = field value for validation +// fieldType = fields +// param = parameter used in validation i.e. gt=0 param would be 0 +type Func func(fl FieldLevel) bool + +var ( + restrictedTags = map[string]struct{}{ + diveTag: {}, + structOnlyTag: {}, + omitempty: {}, + skipValidationTag: {}, + utf8HexComma: {}, + utf8Pipe: {}, + noStructLevelTag: {}, + } + + // BakedInAliasValidators is a default mapping of a single validation tag that + // defines a common or complex set of validation(s) to simplify + // adding validation to structs. + bakedInAliases = map[string]string{ + "iscolor": "hexcolor|rgb|rgba|hsl|hsla", + } + + // BakedInValidators is the default map of ValidationFunc + // you can add, remove or even replace items to suite your needs, + // or even disregard and use your own map if so desired. + bakedInValidators = map[string]Func{ + "required": hasValue, + "len": hasLengthOf, + "min": hasMinOf, + "max": hasMaxOf, + "eq": isEq, + "ne": isNe, + "lt": isLt, + "lte": isLte, + "gt": isGt, + "gte": isGte, + "eqfield": isEqField, + "eqcsfield": isEqCrossStructField, + "necsfield": isNeCrossStructField, + "gtcsfield": isGtCrossStructField, + "gtecsfield": isGteCrossStructField, + "ltcsfield": isLtCrossStructField, + "ltecsfield": isLteCrossStructField, + "nefield": isNeField, + "gtefield": isGteField, + "gtfield": isGtField, + "ltefield": isLteField, + "ltfield": isLtField, + "alpha": isAlpha, + "alphanum": isAlphanum, + "numeric": isNumeric, + "number": isNumber, + "hexadecimal": isHexadecimal, + "hexcolor": isHEXColor, + "rgb": isRGB, + "rgba": isRGBA, + "hsl": isHSL, + "hsla": isHSLA, + "email": isEmail, + "url": isURL, + "uri": isURI, + "base64": isBase64, + "contains": contains, + "containsany": containsAny, + "containsrune": containsRune, + "excludes": excludes, + "excludesall": excludesAll, + "excludesrune": excludesRune, + "isbn": isISBN, + "isbn10": isISBN10, + "isbn13": isISBN13, + "uuid": isUUID, + "uuid3": isUUID3, + "uuid4": isUUID4, + "uuid5": isUUID5, + "ascii": isASCII, + "printascii": isPrintableASCII, + "multibyte": hasMultiByteCharacter, + "datauri": isDataURI, + "latitude": isLatitude, + "longitude": isLongitude, + "ssn": isSSN, + "ipv4": isIPv4, + "ipv6": isIPv6, + "ip": isIP, + "cidrv4": isCIDRv4, + "cidrv6": isCIDRv6, + "cidr": isCIDR, + "tcp4_addr": isTCP4AddrResolvable, + "tcp6_addr": isTCP6AddrResolvable, + "tcp_addr": isTCPAddrResolvable, + "udp4_addr": isUDP4AddrResolvable, + "udp6_addr": isUDP6AddrResolvable, + "udp_addr": isUDPAddrResolvable, + "ip4_addr": isIP4AddrResolvable, + "ip6_addr": isIP6AddrResolvable, + "ip_addr": isIPAddrResolvable, + "unix_addr": isUnixAddrResolvable, + "mac": isMAC, + } +) // IsMAC is the validation function for validating if the field's value is a valid MAC address. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsMAC(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - _, err := net.ParseMAC(field.String()) +func isMAC(fl FieldLevel) bool { + + _, err := net.ParseMAC(fl.Field().String()) + return err == nil } // IsCIDRv4 is the validation function for validating if the field's value is a valid v4 CIDR address. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsCIDRv4(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isCIDRv4(fl FieldLevel) bool { - ip, _, err := net.ParseCIDR(field.String()) + ip, _, err := net.ParseCIDR(fl.Field().String()) return err == nil && ip.To4() != nil } // IsCIDRv6 is the validation function for validating if the field's value is a valid v6 CIDR address. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsCIDRv6(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isCIDRv6(fl FieldLevel) bool { - ip, _, err := net.ParseCIDR(field.String()) + ip, _, err := net.ParseCIDR(fl.Field().String()) return err == nil && ip.To4() == nil } // IsCIDR is the validation function for validating if the field's value is a valid v4 or v6 CIDR address. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsCIDR(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isCIDR(fl FieldLevel) bool { - _, _, err := net.ParseCIDR(field.String()) + _, _, err := net.ParseCIDR(fl.Field().String()) return err == nil } // IsIPv4 is the validation function for validating if a value is a valid v4 IP address. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsIPv4(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isIPv4(fl FieldLevel) bool { - ip := net.ParseIP(field.String()) + ip := net.ParseIP(fl.Field().String()) return ip != nil && ip.To4() != nil } // IsIPv6 is the validation function for validating if the field's value is a valid v6 IP address. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsIPv6(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - ip := net.ParseIP(field.String()) +func isIPv6(fl FieldLevel) bool { + + ip := net.ParseIP(fl.Field().String()) return ip != nil && ip.To4() == nil } // IsIP is the validation function for validating if the field's value is a valid v4 or v6 IP address. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsIP(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isIP(fl FieldLevel) bool { - ip := net.ParseIP(field.String()) + ip := net.ParseIP(fl.Field().String()) return ip != nil } // IsSSN is the validation function for validating if the field's value is a valid SSN. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsSSN(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isSSN(fl FieldLevel) bool { + + field := fl.Field() if field.Len() != 11 { return false @@ -169,22 +184,19 @@ func IsSSN(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Va } // IsLongitude is the validation function for validating if the field's value is a valid longitude coordinate. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsLongitude(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - return longitudeRegex.MatchString(field.String()) +func isLongitude(fl FieldLevel) bool { + return longitudeRegex.MatchString(fl.Field().String()) } // IsLatitude is the validation function for validating if the field's value is a valid latitude coordinate. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsLatitude(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - return latitudeRegex.MatchString(field.String()) +func isLatitude(fl FieldLevel) bool { + return latitudeRegex.MatchString(fl.Field().String()) } // IsDataURI is the validation function for validating if the field's value is a valid data URI. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsDataURI(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isDataURI(fl FieldLevel) bool { - uri := strings.SplitN(field.String(), ",", 2) + uri := strings.SplitN(fl.Field().String(), ",", 2) if len(uri) != 2 { return false @@ -194,14 +206,13 @@ func IsDataURI(v *Validate, topStruct reflect.Value, currentStructOrField reflec return false } - fld := reflect.ValueOf(uri[1]) - - return IsBase64(v, topStruct, currentStructOrField, fld, fld.Type(), fld.Kind(), param) + return base64Regex.MatchString(uri[1]) } // HasMultiByteCharacter is the validation function for validating if the field's value has a multi byte character. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func HasMultiByteCharacter(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func hasMultiByteCharacter(fl FieldLevel) bool { + + field := fl.Field() if field.Len() == 0 { return true @@ -211,52 +222,44 @@ func HasMultiByteCharacter(v *Validate, topStruct reflect.Value, currentStructOr } // IsPrintableASCII is the validation function for validating if the field's value is a valid printable ASCII character. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsPrintableASCII(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - return printableASCIIRegex.MatchString(field.String()) +func isPrintableASCII(fl FieldLevel) bool { + return printableASCIIRegex.MatchString(fl.Field().String()) } // IsASCII is the validation function for validating if the field's value is a valid ASCII character. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsASCII(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - return aSCIIRegex.MatchString(field.String()) +func isASCII(fl FieldLevel) bool { + return aSCIIRegex.MatchString(fl.Field().String()) } // IsUUID5 is the validation function for validating if the field's value is a valid v5 UUID. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsUUID5(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - return uUID5Regex.MatchString(field.String()) +func isUUID5(fl FieldLevel) bool { + return uUID5Regex.MatchString(fl.Field().String()) } // IsUUID4 is the validation function for validating if the field's value is a valid v4 UUID. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsUUID4(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - return uUID4Regex.MatchString(field.String()) +func isUUID4(fl FieldLevel) bool { + return uUID4Regex.MatchString(fl.Field().String()) } // IsUUID3 is the validation function for validating if the field's value is a valid v3 UUID. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsUUID3(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - return uUID3Regex.MatchString(field.String()) +func isUUID3(fl FieldLevel) bool { + return uUID3Regex.MatchString(fl.Field().String()) } // IsUUID is the validation function for validating if the field's value is a valid UUID of any version. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsUUID(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - return uUIDRegex.MatchString(field.String()) +func isUUID(fl FieldLevel) bool { + return uUIDRegex.MatchString(fl.Field().String()) } // IsISBN is the validation function for validating if the field's value is a valid v10 or v13 ISBN. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsISBN(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - return IsISBN10(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) || IsISBN13(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) +func isISBN(fl FieldLevel) bool { + return isISBN10(fl) || isISBN13(fl) } // IsISBN13 is the validation function for validating if the field's value is a valid v13 ISBN. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsISBN13(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isISBN13(fl FieldLevel) bool { - s := strings.Replace(strings.Replace(field.String(), "-", "", 4), " ", "", 4) + s := strings.Replace(strings.Replace(fl.Field().String(), "-", "", 4), " ", "", 4) if !iSBN13Regex.MatchString(s) { return false @@ -275,10 +278,9 @@ func IsISBN13(v *Validate, topStruct reflect.Value, currentStructOrField reflect } // IsISBN10 is the validation function for validating if the field's value is a valid v10 ISBN. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsISBN10(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isISBN10(fl FieldLevel) bool { - s := strings.Replace(strings.Replace(field.String(), "-", "", 3), " ", "", 3) + s := strings.Replace(strings.Replace(fl.Field().String(), "-", "", 3), " ", "", 3) if !iSBN10Regex.MatchString(s) { return false @@ -301,54 +303,51 @@ func IsISBN10(v *Validate, topStruct reflect.Value, currentStructOrField reflect } // ExcludesRune is the validation function for validating that the field's value does not contain the rune specified within the param. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func ExcludesRune(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - return !ContainsRune(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) +func excludesRune(fl FieldLevel) bool { + return !containsRune(fl) } // ExcludesAll is the validation function for validating that the field's value does not contain any of the characters specified within the param. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func ExcludesAll(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - return !ContainsAny(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) +func excludesAll(fl FieldLevel) bool { + return !containsAny(fl) } // Excludes is the validation function for validating that the field's value does not contain the text specified within the param. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func Excludes(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - return !Contains(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) +func excludes(fl FieldLevel) bool { + return !contains(fl) } // ContainsRune is the validation function for validating that the field's value contains the rune specified within the param. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func ContainsRune(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - r, _ := utf8.DecodeRuneInString(param) +func containsRune(fl FieldLevel) bool { - return strings.ContainsRune(field.String(), r) + r, _ := utf8.DecodeRuneInString(fl.Param()) + + return strings.ContainsRune(fl.Field().String(), r) } // ContainsAny is the validation function for validating that the field's value contains any of the characters specified within the param. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func ContainsAny(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - return strings.ContainsAny(field.String(), param) +func containsAny(fl FieldLevel) bool { + return strings.ContainsAny(fl.Field().String(), fl.Param()) } // Contains is the validation function for validating that the field's value contains the text specified within the param. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func Contains(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - return strings.Contains(field.String(), param) +func contains(fl FieldLevel) bool { + return strings.Contains(fl.Field().String(), fl.Param()) } // IsNeField is the validation function for validating if the current field's value is not equal to the field specified by the param's value. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsNeField(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isNeField(fl FieldLevel) bool { - currentField, currentKind, ok := v.GetStructFieldOK(currentStructOrField, param) + field := fl.Field() + kind := field.Kind() - if !ok || currentKind != fieldKind { + currentField, currentKind, ok := fl.GetStructFieldOK() + + if !ok || currentKind != kind { return true } - switch fieldKind { + switch kind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int() != currentField.Int() @@ -364,6 +363,8 @@ func IsNeField(v *Validate, topStruct reflect.Value, currentStructOrField reflec case reflect.Struct: + fieldType := field.Type() + // Not Same underlying type i.e. struct and time if fieldType != currentField.Type() { return true @@ -384,21 +385,22 @@ func IsNeField(v *Validate, topStruct reflect.Value, currentStructOrField reflec } // IsNe is the validation function for validating that the field's value does not equal the provided param value. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsNe(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - return !IsEq(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) +func isNe(fl FieldLevel) bool { + return !isEq(fl) } // IsLteCrossStructField is the validation function for validating if the current field's value is less than or equal to the field, within a separate struct, specified by the param's value. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsLteCrossStructField(v *Validate, topStruct reflect.Value, current reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isLteCrossStructField(fl FieldLevel) bool { - topField, topKind, ok := v.GetStructFieldOK(topStruct, param) - if !ok || topKind != fieldKind { + field := fl.Field() + kind := field.Kind() + + topField, topKind, ok := fl.GetStructFieldOK() + if !ok || topKind != kind { return false } - switch fieldKind { + switch kind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int() <= topField.Int() @@ -414,6 +416,8 @@ func IsLteCrossStructField(v *Validate, topStruct reflect.Value, current reflect case reflect.Struct: + fieldType := field.Type() + // Not Same underlying type i.e. struct and time if fieldType != topField.Type() { return false @@ -434,14 +438,17 @@ func IsLteCrossStructField(v *Validate, topStruct reflect.Value, current reflect // IsLtCrossStructField is the validation function for validating if the current field's value is less than the field, within a separate struct, specified by the param's value. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsLtCrossStructField(v *Validate, topStruct reflect.Value, current reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isLtCrossStructField(fl FieldLevel) bool { - topField, topKind, ok := v.GetStructFieldOK(topStruct, param) - if !ok || topKind != fieldKind { + field := fl.Field() + kind := field.Kind() + + topField, topKind, ok := fl.GetStructFieldOK() + if !ok || topKind != kind { return false } - switch fieldKind { + switch kind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int() < topField.Int() @@ -457,6 +464,8 @@ func IsLtCrossStructField(v *Validate, topStruct reflect.Value, current reflect. case reflect.Struct: + fieldType := field.Type() + // Not Same underlying type i.e. struct and time if fieldType != topField.Type() { return false @@ -476,15 +485,17 @@ func IsLtCrossStructField(v *Validate, topStruct reflect.Value, current reflect. } // IsGteCrossStructField is the validation function for validating if the current field's value is greater than or equal to the field, within a separate struct, specified by the param's value. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsGteCrossStructField(v *Validate, topStruct reflect.Value, current reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isGteCrossStructField(fl FieldLevel) bool { + + field := fl.Field() + kind := field.Kind() - topField, topKind, ok := v.GetStructFieldOK(topStruct, param) - if !ok || topKind != fieldKind { + topField, topKind, ok := fl.GetStructFieldOK() + if !ok || topKind != kind { return false } - switch fieldKind { + switch kind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int() >= topField.Int() @@ -500,6 +511,8 @@ func IsGteCrossStructField(v *Validate, topStruct reflect.Value, current reflect case reflect.Struct: + fieldType := field.Type() + // Not Same underlying type i.e. struct and time if fieldType != topField.Type() { return false @@ -519,15 +532,17 @@ func IsGteCrossStructField(v *Validate, topStruct reflect.Value, current reflect } // IsGtCrossStructField is the validation function for validating if the current field's value is greater than the field, within a separate struct, specified by the param's value. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsGtCrossStructField(v *Validate, topStruct reflect.Value, current reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isGtCrossStructField(fl FieldLevel) bool { + + field := fl.Field() + kind := field.Kind() - topField, topKind, ok := v.GetStructFieldOK(topStruct, param) - if !ok || topKind != fieldKind { + topField, topKind, ok := fl.GetStructFieldOK() + if !ok || topKind != kind { return false } - switch fieldKind { + switch kind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int() > topField.Int() @@ -543,6 +558,8 @@ func IsGtCrossStructField(v *Validate, topStruct reflect.Value, current reflect. case reflect.Struct: + fieldType := field.Type() + // Not Same underlying type i.e. struct and time if fieldType != topField.Type() { return false @@ -562,15 +579,17 @@ func IsGtCrossStructField(v *Validate, topStruct reflect.Value, current reflect. } // IsNeCrossStructField is the validation function for validating that the current field's value is not equal to the field, within a separate struct, specified by the param's value. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsNeCrossStructField(v *Validate, topStruct reflect.Value, current reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isNeCrossStructField(fl FieldLevel) bool { - topField, currentKind, ok := v.GetStructFieldOK(topStruct, param) - if !ok || currentKind != fieldKind { + field := fl.Field() + kind := field.Kind() + + topField, currentKind, ok := fl.GetStructFieldOK() + if !ok || currentKind != kind { return true } - switch fieldKind { + switch kind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return topField.Int() != field.Int() @@ -586,6 +605,8 @@ func IsNeCrossStructField(v *Validate, topStruct reflect.Value, current reflect. case reflect.Struct: + fieldType := field.Type() + // Not Same underlying type i.e. struct and time if fieldType != topField.Type() { return true @@ -605,15 +626,17 @@ func IsNeCrossStructField(v *Validate, topStruct reflect.Value, current reflect. } // IsEqCrossStructField is the validation function for validating that the current field's value is equal to the field, within a separate struct, specified by the param's value. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsEqCrossStructField(v *Validate, topStruct reflect.Value, current reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isEqCrossStructField(fl FieldLevel) bool { + + field := fl.Field() + kind := field.Kind() - topField, topKind, ok := v.GetStructFieldOK(topStruct, param) - if !ok || topKind != fieldKind { + topField, topKind, ok := fl.GetStructFieldOK() + if !ok || topKind != kind { return false } - switch fieldKind { + switch kind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return topField.Int() == field.Int() @@ -629,6 +652,8 @@ func IsEqCrossStructField(v *Validate, topStruct reflect.Value, current reflect. case reflect.Struct: + fieldType := field.Type() + // Not Same underlying type i.e. struct and time if fieldType != topField.Type() { return false @@ -648,15 +673,17 @@ func IsEqCrossStructField(v *Validate, topStruct reflect.Value, current reflect. } // IsEqField is the validation function for validating if the current field's value is equal to the field specified by the param's value. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsEqField(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isEqField(fl FieldLevel) bool { - currentField, currentKind, ok := v.GetStructFieldOK(currentStructOrField, param) - if !ok || currentKind != fieldKind { + field := fl.Field() + kind := field.Kind() + + currentField, currentKind, ok := fl.GetStructFieldOK() + if !ok || currentKind != kind { return false } - switch fieldKind { + switch kind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int() == currentField.Int() @@ -672,6 +699,8 @@ func IsEqField(v *Validate, topStruct reflect.Value, currentStructOrField reflec case reflect.Struct: + fieldType := field.Type() + // Not Same underlying type i.e. struct and time if fieldType != currentField.Type() { return false @@ -692,10 +721,12 @@ func IsEqField(v *Validate, topStruct reflect.Value, currentStructOrField reflec } // IsEq is the validation function for validating if the current field's value is equal to the param's value. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsEq(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isEq(fl FieldLevel) bool { + + field := fl.Field() + param := fl.Param() - switch fieldKind { + switch field.Kind() { case reflect.String: return field.String() == param @@ -725,16 +756,16 @@ func IsEq(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Val } // IsBase64 is the validation function for validating if the current field's value is a valid base 64. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsBase64(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - return base64Regex.MatchString(field.String()) +func isBase64(fl FieldLevel) bool { + return base64Regex.MatchString(fl.Field().String()) } // IsURI is the validation function for validating if the current field's value is a valid URI. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsURI(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isURI(fl FieldLevel) bool { - switch fieldKind { + field := fl.Field() + + switch field.Kind() { case reflect.String: @@ -746,7 +777,7 @@ func IsURI(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Va s = s[:i] } - if s == blank { + if len(s) == 0 { return false } @@ -759,10 +790,11 @@ func IsURI(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Va } // IsURL is the validation function for validating if the current field's value is a valid URL. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsURL(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isURL(fl FieldLevel) bool { + + field := fl.Field() - switch fieldKind { + switch field.Kind() { case reflect.String: @@ -775,13 +807,13 @@ func IsURL(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Va s = s[:i] } - if s == blank { + if len(s) == 0 { return false } url, err := url.ParseRequestURI(s) - if err != nil || url.Scheme == blank { + if err != nil || url.Scheme == "" { return false } @@ -792,93 +824,85 @@ func IsURL(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Va } // IsEmail is the validation function for validating if the current field's value is a valid email address. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsEmail(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - return emailRegex.MatchString(field.String()) +func isEmail(fl FieldLevel) bool { + return emailRegex.MatchString(fl.Field().String()) } // IsHSLA is the validation function for validating if the current field's value is a valid HSLA color. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsHSLA(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - return hslaRegex.MatchString(field.String()) +func isHSLA(fl FieldLevel) bool { + return hslaRegex.MatchString(fl.Field().String()) } // IsHSL is the validation function for validating if the current field's value is a valid HSL color. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsHSL(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - return hslRegex.MatchString(field.String()) +func isHSL(fl FieldLevel) bool { + return hslRegex.MatchString(fl.Field().String()) } // IsRGBA is the validation function for validating if the current field's value is a valid RGBA color. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsRGBA(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - return rgbaRegex.MatchString(field.String()) +func isRGBA(fl FieldLevel) bool { + return rgbaRegex.MatchString(fl.Field().String()) } // IsRGB is the validation function for validating if the current field's value is a valid RGB color. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsRGB(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - return rgbRegex.MatchString(field.String()) +func isRGB(fl FieldLevel) bool { + return rgbRegex.MatchString(fl.Field().String()) } // IsHEXColor is the validation function for validating if the current field's value is a valid HEX color. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsHEXColor(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - return hexcolorRegex.MatchString(field.String()) +func isHEXColor(fl FieldLevel) bool { + return hexcolorRegex.MatchString(fl.Field().String()) } // IsHexadecimal is the validation function for validating if the current field's value is a valid hexadecimal. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsHexadecimal(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - return hexadecimalRegex.MatchString(field.String()) +func isHexadecimal(fl FieldLevel) bool { + return hexadecimalRegex.MatchString(fl.Field().String()) } // IsNumber is the validation function for validating if the current field's value is a valid number. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsNumber(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - return numberRegex.MatchString(field.String()) +func isNumber(fl FieldLevel) bool { + return numberRegex.MatchString(fl.Field().String()) } // IsNumeric is the validation function for validating if the current field's value is a valid numeric value. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsNumeric(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - return numericRegex.MatchString(field.String()) +func isNumeric(fl FieldLevel) bool { + return numericRegex.MatchString(fl.Field().String()) } // IsAlphanum is the validation function for validating if the current field's value is a valid alphanumeric value. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsAlphanum(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - return alphaNumericRegex.MatchString(field.String()) +func isAlphanum(fl FieldLevel) bool { + return alphaNumericRegex.MatchString(fl.Field().String()) } // IsAlpha is the validation function for validating if the current field's value is a valid alpha value. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsAlpha(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - return alphaRegex.MatchString(field.String()) +func isAlpha(fl FieldLevel) bool { + return alphaRegex.MatchString(fl.Field().String()) } // HasValue is the validation function for validating if the current field's value is not the default static value. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func HasValue(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func hasValue(fl FieldLevel) bool { + + field := fl.Field() - switch fieldKind { + switch field.Kind() { case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func: return !field.IsNil() default: - return field.IsValid() && field.Interface() != reflect.Zero(fieldType).Interface() + return field.IsValid() && field.Interface() != reflect.Zero(field.Type()).Interface() } } // IsGteField is the validation function for validating if the current field's value is greater than or equal to the field specified by the param's value. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsGteField(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isGteField(fl FieldLevel) bool { + + field := fl.Field() + kind := field.Kind() - currentField, currentKind, ok := v.GetStructFieldOK(currentStructOrField, param) - if !ok || currentKind != fieldKind { + currentField, currentKind, ok := fl.GetStructFieldOK() + if !ok || currentKind != kind { return false } - switch fieldKind { + switch kind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: @@ -894,6 +918,8 @@ func IsGteField(v *Validate, topStruct reflect.Value, currentStructOrField refle case reflect.Struct: + fieldType := field.Type() + // Not Same underlying type i.e. struct and time if fieldType != currentField.Type() { return false @@ -913,15 +939,17 @@ func IsGteField(v *Validate, topStruct reflect.Value, currentStructOrField refle } // IsGtField is the validation function for validating if the current field's value is greater than the field specified by the param's value. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsGtField(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isGtField(fl FieldLevel) bool { + + field := fl.Field() + kind := field.Kind() - currentField, currentKind, ok := v.GetStructFieldOK(currentStructOrField, param) - if !ok || currentKind != fieldKind { + currentField, currentKind, ok := fl.GetStructFieldOK() + if !ok || currentKind != kind { return false } - switch fieldKind { + switch kind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: @@ -937,6 +965,8 @@ func IsGtField(v *Validate, topStruct reflect.Value, currentStructOrField reflec case reflect.Struct: + fieldType := field.Type() + // Not Same underlying type i.e. struct and time if fieldType != currentField.Type() { return false @@ -956,10 +986,12 @@ func IsGtField(v *Validate, topStruct reflect.Value, currentStructOrField reflec } // IsGte is the validation function for validating if the current field's value is greater than or equal to the param's value. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsGte(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isGte(fl FieldLevel) bool { - switch fieldKind { + field := fl.Field() + param := fl.Param() + + switch field.Kind() { case reflect.String: p := asInt(param) @@ -988,7 +1020,7 @@ func IsGte(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Va case reflect.Struct: - if fieldType == timeType || fieldType == timePtrType { + if field.Type() == timeType { now := time.Now().UTC() t := field.Interface().(time.Time) @@ -1001,10 +1033,12 @@ func IsGte(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Va } // IsGt is the validation function for validating if the current field's value is greater than the param's value. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsGt(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isGt(fl FieldLevel) bool { - switch fieldKind { + field := fl.Field() + param := fl.Param() + + switch field.Kind() { case reflect.String: p := asInt(param) @@ -1032,7 +1066,7 @@ func IsGt(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Val return field.Float() > p case reflect.Struct: - if fieldType == timeType || fieldType == timePtrType { + if field.Type() == timeType { return field.Interface().(time.Time).After(time.Now().UTC()) } @@ -1042,10 +1076,12 @@ func IsGt(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Val } // HasLengthOf is the validation function for validating if the current field's value is equal to the param's value. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func HasLengthOf(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func hasLengthOf(fl FieldLevel) bool { - switch fieldKind { + field := fl.Field() + param := fl.Param() + + switch field.Kind() { case reflect.String: p := asInt(param) @@ -1077,22 +1113,22 @@ func HasLengthOf(v *Validate, topStruct reflect.Value, currentStructOrField refl } // HasMinOf is the validation function for validating if the current field's value is greater than or equal to the param's value. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func HasMinOf(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - - return IsGte(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) +func hasMinOf(fl FieldLevel) bool { + return isGte(fl) } // IsLteField is the validation function for validating if the current field's value is less than or equal to the field specified by the param's value. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsLteField(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isLteField(fl FieldLevel) bool { - currentField, currentKind, ok := v.GetStructFieldOK(currentStructOrField, param) - if !ok || currentKind != fieldKind { + field := fl.Field() + kind := field.Kind() + + currentField, currentKind, ok := fl.GetStructFieldOK() + if !ok || currentKind != kind { return false } - switch fieldKind { + switch kind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: @@ -1108,6 +1144,8 @@ func IsLteField(v *Validate, topStruct reflect.Value, currentStructOrField refle case reflect.Struct: + fieldType := field.Type() + // Not Same underlying type i.e. struct and time if fieldType != currentField.Type() { return false @@ -1127,15 +1165,17 @@ func IsLteField(v *Validate, topStruct reflect.Value, currentStructOrField refle } // IsLtField is the validation function for validating if the current field's value is less than the field specified by the param's value. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsLtField(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isLtField(fl FieldLevel) bool { + + field := fl.Field() + kind := field.Kind() - currentField, currentKind, ok := v.GetStructFieldOK(currentStructOrField, param) - if !ok || currentKind != fieldKind { + currentField, currentKind, ok := fl.GetStructFieldOK() + if !ok || currentKind != kind { return false } - switch fieldKind { + switch kind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: @@ -1151,6 +1191,8 @@ func IsLtField(v *Validate, topStruct reflect.Value, currentStructOrField reflec case reflect.Struct: + fieldType := field.Type() + // Not Same underlying type i.e. struct and time if fieldType != currentField.Type() { return false @@ -1170,10 +1212,12 @@ func IsLtField(v *Validate, topStruct reflect.Value, currentStructOrField reflec } // IsLte is the validation function for validating if the current field's value is less than or equal to the param's value. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsLte(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isLte(fl FieldLevel) bool { + + field := fl.Field() + param := fl.Param() - switch fieldKind { + switch field.Kind() { case reflect.String: p := asInt(param) @@ -1202,7 +1246,7 @@ func IsLte(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Va case reflect.Struct: - if fieldType == timeType || fieldType == timePtrType { + if field.Type() == timeType { now := time.Now().UTC() t := field.Interface().(time.Time) @@ -1215,10 +1259,12 @@ func IsLte(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Va } // IsLt is the validation function for validating if the current field's value is less than the param's value. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsLt(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isLt(fl FieldLevel) bool { + + field := fl.Field() + param := fl.Param() - switch fieldKind { + switch field.Kind() { case reflect.String: p := asInt(param) @@ -1247,7 +1293,7 @@ func IsLt(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Val case reflect.Struct: - if fieldType == timeType || fieldType == timePtrType { + if field.Type() == timeType { return field.Interface().(time.Time).Before(time.Now().UTC()) } @@ -1257,144 +1303,141 @@ func IsLt(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Val } // HasMaxOf is the validation function for validating if the current field's value is less than or equal to the param's value. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func HasMaxOf(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - return IsLte(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) +func hasMaxOf(fl FieldLevel) bool { + return isLte(fl) } // IsTCP4AddrResolvable is the validation function for validating if the field's value is a resolvable tcp4 address. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsTCP4AddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isTCP4AddrResolvable(fl FieldLevel) bool { - if !isIP4Addr(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) { + if !isIP4Addr(fl) { return false } - _, err := net.ResolveTCPAddr("tcp4", field.String()) + _, err := net.ResolveTCPAddr("tcp4", fl.Field().String()) return err == nil } // IsTCP6AddrResolvable is the validation function for validating if the field's value is a resolvable tcp6 address. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsTCP6AddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isTCP6AddrResolvable(fl FieldLevel) bool { - if !isIP6Addr(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) { + if !isIP6Addr(fl) { return false } - _, err := net.ResolveTCPAddr("tcp6", field.String()) + _, err := net.ResolveTCPAddr("tcp6", fl.Field().String()) + return err == nil } // IsTCPAddrResolvable is the validation function for validating if the field's value is a resolvable tcp address. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsTCPAddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isTCPAddrResolvable(fl FieldLevel) bool { - if !isIP4Addr(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) && - !isIP6Addr(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) { + if !isIP4Addr(fl) && !isIP6Addr(fl) { return false } - _, err := net.ResolveTCPAddr("tcp", field.String()) + _, err := net.ResolveTCPAddr("tcp", fl.Field().String()) + return err == nil } // IsUDP4AddrResolvable is the validation function for validating if the field's value is a resolvable udp4 address. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsUDP4AddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isUDP4AddrResolvable(fl FieldLevel) bool { - if !isIP4Addr(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) { + if !isIP4Addr(fl) { return false } - _, err := net.ResolveUDPAddr("udp4", field.String()) + _, err := net.ResolveUDPAddr("udp4", fl.Field().String()) + return err == nil } // IsUDP6AddrResolvable is the validation function for validating if the field's value is a resolvable udp6 address. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsUDP6AddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isUDP6AddrResolvable(fl FieldLevel) bool { - if !isIP6Addr(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) { + if !isIP6Addr(fl) { return false } - _, err := net.ResolveUDPAddr("udp6", field.String()) + _, err := net.ResolveUDPAddr("udp6", fl.Field().String()) + return err == nil } // IsUDPAddrResolvable is the validation function for validating if the field's value is a resolvable udp address. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsUDPAddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isUDPAddrResolvable(fl FieldLevel) bool { - if !isIP4Addr(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) && - !isIP6Addr(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) { + if !isIP4Addr(fl) && !isIP6Addr(fl) { return false } - _, err := net.ResolveUDPAddr("udp", field.String()) + _, err := net.ResolveUDPAddr("udp", fl.Field().String()) + return err == nil } // IsIP4AddrResolvable is the validation function for validating if the field's value is a resolvable ip4 address. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsIP4AddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isIP4AddrResolvable(fl FieldLevel) bool { - if !IsIPv4(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) { + if !isIPv4(fl) { return false } - _, err := net.ResolveIPAddr("ip4", field.String()) + _, err := net.ResolveIPAddr("ip4", fl.Field().String()) + return err == nil } // IsIP6AddrResolvable is the validation function for validating if the field's value is a resolvable ip6 address. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsIP6AddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isIP6AddrResolvable(fl FieldLevel) bool { - if !IsIPv6(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) { + if !isIPv6(fl) { return false } - _, err := net.ResolveIPAddr("ip6", field.String()) + _, err := net.ResolveIPAddr("ip6", fl.Field().String()) + return err == nil } // IsIPAddrResolvable is the validation function for validating if the field's value is a resolvable ip address. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsIPAddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +func isIPAddrResolvable(fl FieldLevel) bool { - if !IsIP(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) { + if !isIP(fl) { return false } - _, err := net.ResolveIPAddr("ip", field.String()) + _, err := net.ResolveIPAddr("ip", fl.Field().String()) + return err == nil } // IsUnixAddrResolvable is the validation function for validating if the field's value is a resolvable unix address. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func IsUnixAddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - _, err := net.ResolveUnixAddr("unix", field.String()) +func isUnixAddrResolvable(fl FieldLevel) bool { + + _, err := net.ResolveUnixAddr("unix", fl.Field().String()) + return err == nil } -func isIP4Addr(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - val := field.String() +func isIP4Addr(fl FieldLevel) bool { + + val := fl.Field().String() if idx := strings.LastIndex(val, ":"); idx != -1 { val = val[0:idx] } - if !IsIPv4(v, topStruct, currentStructOrField, reflect.ValueOf(val), fieldType, fieldKind, param) { - return false - } + ip := net.ParseIP(val) - return true + return ip != nil && ip.To4() != nil } -func isIP6Addr(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - val := field.String() +func isIP6Addr(fl FieldLevel) bool { + + val := fl.Field().String() if idx := strings.LastIndex(val, ":"); idx != -1 { if idx != 0 && val[idx-1:idx] == "]" { @@ -1402,9 +1445,7 @@ func isIP6Addr(v *Validate, topStruct reflect.Value, currentStructOrField reflec } } - if !IsIPv6(v, topStruct, currentStructOrField, reflect.ValueOf(val), fieldType, fieldKind, param) { - return false - } + ip := net.ParseIP(val) - return true + return ip != nil && ip.To4() == nil } diff --git a/benchmarks_test.go b/benchmarks_test.go index 84db743..c369243 100644 --- a/benchmarks_test.go +++ b/benchmarks_test.go @@ -8,28 +8,38 @@ import ( func BenchmarkFieldSuccess(b *testing.B) { + validate := New() + var s *string tmp := "1" s = &tmp + b.ReportAllocs() + for n := 0; n < b.N; n++ { - validate.Field(s, "len=1") + validate.Var(s, "len=1") } } func BenchmarkFieldFailure(b *testing.B) { + validate := New() + var s *string tmp := "12" s = &tmp + b.ReportAllocs() + for n := 0; n < b.N; n++ { - validate.Field(s, "len=1") + validate.Var(s, "len=1") } } func BenchmarkFieldDiveSuccess(b *testing.B) { + validate := New() + m := make([]*string, 3) t1 := "val1" t2 := "val2" @@ -39,13 +49,17 @@ func BenchmarkFieldDiveSuccess(b *testing.B) { m[1] = &t2 m[2] = &t3 + b.ReportAllocs() + for n := 0; n < b.N; n++ { - validate.Field(m, "required,dive,required") + validate.Var(m, "required,dive,required") } } func BenchmarkFieldDiveFailure(b *testing.B) { + validate := New() + m := make([]*string, 3) t1 := "val1" t2 := "" @@ -55,65 +69,84 @@ func BenchmarkFieldDiveFailure(b *testing.B) { m[1] = &t2 m[2] = &t3 + b.ReportAllocs() + for n := 0; n < b.N; n++ { - validate.Field(m, "required,dive,required") + validate.Var(m, "required,dive,required") } } func BenchmarkFieldCustomTypeSuccess(b *testing.B) { + validate := New() validate.RegisterCustomTypeFunc(ValidateValuerType, (*sql.Valuer)(nil), valuer{}) val := valuer{ Name: "1", } + b.ReportAllocs() + for n := 0; n < b.N; n++ { - validate.Field(val, "len=1") + validate.Var(val, "len=1") } } func BenchmarkFieldCustomTypeFailure(b *testing.B) { + validate := New() validate.RegisterCustomTypeFunc(ValidateValuerType, (*sql.Valuer)(nil), valuer{}) val := valuer{} + b.ReportAllocs() + for n := 0; n < b.N; n++ { - validate.Field(val, "len=1") + validate.Var(val, "len=1") } } func BenchmarkFieldOrTagSuccess(b *testing.B) { + validate := New() + var s *string tmp := "rgba(0,0,0,1)" s = &tmp + b.ReportAllocs() + for n := 0; n < b.N; n++ { - validate.Field(s, "rgb|rgba") + validate.Var(s, "rgb|rgba") } } func BenchmarkFieldOrTagFailure(b *testing.B) { + validate := New() + var s *string tmp := "#000" s = &tmp + b.ReportAllocs() + for n := 0; n < b.N; n++ { - validate.Field(s, "rgb|rgba") + validate.Var(s, "rgb|rgba") } } func BenchmarkStructLevelValidationSuccess(b *testing.B) { + validate := New() validate.RegisterStructValidation(StructValidationTestStructSuccess, TestStruct{}) tst := &TestStruct{ String: "good value", } + b.ReportAllocs() + for n := 0; n < b.N; n++ { validate.Struct(tst) } @@ -121,12 +154,15 @@ func BenchmarkStructLevelValidationSuccess(b *testing.B) { func BenchmarkStructLevelValidationFailure(b *testing.B) { + validate := New() validate.RegisterStructValidation(StructValidationTestStruct, TestStruct{}) tst := &TestStruct{ String: "good value", } + b.ReportAllocs() + for n := 0; n < b.N; n++ { validate.Struct(tst) } @@ -134,6 +170,7 @@ func BenchmarkStructLevelValidationFailure(b *testing.B) { func BenchmarkStructSimpleCustomTypeSuccess(b *testing.B) { + validate := New() validate.RegisterCustomTypeFunc(ValidateValuerType, (*sql.Valuer)(nil), valuer{}) val := valuer{ @@ -147,6 +184,8 @@ func BenchmarkStructSimpleCustomTypeSuccess(b *testing.B) { validFoo := &Foo{Valuer: val, IntValue: 7} + b.ReportAllocs() + for n := 0; n < b.N; n++ { validate.Struct(validFoo) } @@ -154,6 +193,7 @@ func BenchmarkStructSimpleCustomTypeSuccess(b *testing.B) { func BenchmarkStructSimpleCustomTypeFailure(b *testing.B) { + validate := New() validate.RegisterCustomTypeFunc(ValidateValuerType, (*sql.Valuer)(nil), valuer{}) val := valuer{} @@ -165,6 +205,8 @@ func BenchmarkStructSimpleCustomTypeFailure(b *testing.B) { validFoo := &Foo{Valuer: val, IntValue: 3} + b.ReportAllocs() + for n := 0; n < b.N; n++ { validate.Struct(validFoo) } @@ -172,6 +214,8 @@ func BenchmarkStructSimpleCustomTypeFailure(b *testing.B) { func BenchmarkStructPartialSuccess(b *testing.B) { + validate := New() + type Test struct { Name string `validate:"required"` NickName string `validate:"required"` @@ -181,6 +225,8 @@ func BenchmarkStructPartialSuccess(b *testing.B) { Name: "Joey Bloggs", } + b.ReportAllocs() + for n := 0; n < b.N; n++ { validate.StructPartial(test, "Name") } @@ -188,6 +234,8 @@ func BenchmarkStructPartialSuccess(b *testing.B) { func BenchmarkStructPartialFailure(b *testing.B) { + validate := New() + type Test struct { Name string `validate:"required"` NickName string `validate:"required"` @@ -197,6 +245,8 @@ func BenchmarkStructPartialFailure(b *testing.B) { Name: "Joey Bloggs", } + b.ReportAllocs() + for n := 0; n < b.N; n++ { validate.StructPartial(test, "NickName") } @@ -204,6 +254,8 @@ func BenchmarkStructPartialFailure(b *testing.B) { func BenchmarkStructExceptSuccess(b *testing.B) { + validate := New() + type Test struct { Name string `validate:"required"` NickName string `validate:"required"` @@ -213,6 +265,8 @@ func BenchmarkStructExceptSuccess(b *testing.B) { Name: "Joey Bloggs", } + b.ReportAllocs() + for n := 0; n < b.N; n++ { validate.StructPartial(test, "Nickname") } @@ -220,6 +274,8 @@ func BenchmarkStructExceptSuccess(b *testing.B) { func BenchmarkStructExceptFailure(b *testing.B) { + validate := New() + type Test struct { Name string `validate:"required"` NickName string `validate:"required"` @@ -229,6 +285,8 @@ func BenchmarkStructExceptFailure(b *testing.B) { Name: "Joey Bloggs", } + b.ReportAllocs() + for n := 0; n < b.N; n++ { validate.StructPartial(test, "Name") } @@ -236,6 +294,8 @@ func BenchmarkStructExceptFailure(b *testing.B) { func BenchmarkStructSimpleCrossFieldSuccess(b *testing.B) { + validate := New() + type Test struct { Start time.Time End time.Time `validate:"gtfield=Start"` @@ -249,6 +309,8 @@ func BenchmarkStructSimpleCrossFieldSuccess(b *testing.B) { End: then, } + b.ReportAllocs() + for n := 0; n < b.N; n++ { validate.Struct(test) } @@ -256,6 +318,8 @@ func BenchmarkStructSimpleCrossFieldSuccess(b *testing.B) { func BenchmarkStructSimpleCrossFieldFailure(b *testing.B) { + validate := New() + type Test struct { Start time.Time End time.Time `validate:"gtfield=Start"` @@ -269,6 +333,8 @@ func BenchmarkStructSimpleCrossFieldFailure(b *testing.B) { End: then, } + b.ReportAllocs() + for n := 0; n < b.N; n++ { validate.Struct(test) } @@ -276,6 +342,8 @@ func BenchmarkStructSimpleCrossFieldFailure(b *testing.B) { func BenchmarkStructSimpleCrossStructCrossFieldSuccess(b *testing.B) { + validate := New() + type Inner struct { Start time.Time } @@ -296,6 +364,8 @@ func BenchmarkStructSimpleCrossStructCrossFieldSuccess(b *testing.B) { CreatedAt: now, } + b.ReportAllocs() + for n := 0; n < b.N; n++ { validate.Struct(outer) } @@ -303,6 +373,8 @@ func BenchmarkStructSimpleCrossStructCrossFieldSuccess(b *testing.B) { func BenchmarkStructSimpleCrossStructCrossFieldFailure(b *testing.B) { + validate := New() + type Inner struct { Start time.Time } @@ -324,6 +396,8 @@ func BenchmarkStructSimpleCrossStructCrossFieldFailure(b *testing.B) { CreatedAt: now, } + b.ReportAllocs() + for n := 0; n < b.N; n++ { validate.Struct(outer) } @@ -331,6 +405,8 @@ func BenchmarkStructSimpleCrossStructCrossFieldFailure(b *testing.B) { func BenchmarkStructSimpleSuccess(b *testing.B) { + validate := New() + type Foo struct { StringValue string `validate:"min=5,max=10"` IntValue int `validate:"min=5,max=10"` @@ -338,6 +414,8 @@ func BenchmarkStructSimpleSuccess(b *testing.B) { validFoo := &Foo{StringValue: "Foobar", IntValue: 7} + b.ReportAllocs() + for n := 0; n < b.N; n++ { validate.Struct(validFoo) } @@ -345,6 +423,8 @@ func BenchmarkStructSimpleSuccess(b *testing.B) { func BenchmarkStructSimpleFailure(b *testing.B) { + validate := New() + type Foo struct { StringValue string `validate:"min=5,max=10"` IntValue int `validate:"min=5,max=10"` @@ -352,6 +432,8 @@ func BenchmarkStructSimpleFailure(b *testing.B) { invalidFoo := &Foo{StringValue: "Fo", IntValue: 3} + b.ReportAllocs() + for n := 0; n < b.N; n++ { validate.Struct(invalidFoo) } @@ -359,6 +441,8 @@ func BenchmarkStructSimpleFailure(b *testing.B) { func BenchmarkStructSimpleSuccessParallel(b *testing.B) { + validate := New() + type Foo struct { StringValue string `validate:"min=5,max=10"` IntValue int `validate:"min=5,max=10"` @@ -366,6 +450,8 @@ func BenchmarkStructSimpleSuccessParallel(b *testing.B) { validFoo := &Foo{StringValue: "Foobar", IntValue: 7} + b.ReportAllocs() + b.RunParallel(func(pb *testing.PB) { for pb.Next() { validate.Struct(validFoo) @@ -375,6 +461,8 @@ func BenchmarkStructSimpleSuccessParallel(b *testing.B) { func BenchmarkStructSimpleFailureParallel(b *testing.B) { + validate := New() + type Foo struct { StringValue string `validate:"min=5,max=10"` IntValue int `validate:"min=5,max=10"` @@ -382,6 +470,8 @@ func BenchmarkStructSimpleFailureParallel(b *testing.B) { invalidFoo := &Foo{StringValue: "Fo", IntValue: 3} + b.ReportAllocs() + b.RunParallel(func(pb *testing.PB) { for pb.Next() { validate.Struct(invalidFoo) @@ -391,6 +481,8 @@ func BenchmarkStructSimpleFailureParallel(b *testing.B) { func BenchmarkStructComplexSuccess(b *testing.B) { + validate := New() + tSuccess := &TestString{ Required: "Required", Len: "length==10", @@ -418,6 +510,8 @@ func BenchmarkStructComplexSuccess(b *testing.B) { }, } + b.ReportAllocs() + for n := 0; n < b.N; n++ { validate.Struct(tSuccess) } @@ -425,6 +519,8 @@ func BenchmarkStructComplexSuccess(b *testing.B) { func BenchmarkStructComplexFailure(b *testing.B) { + validate := New() + tFail := &TestString{ Required: "", Len: "", @@ -449,6 +545,8 @@ func BenchmarkStructComplexFailure(b *testing.B) { }, } + b.ReportAllocs() + for n := 0; n < b.N; n++ { validate.Struct(tFail) } @@ -456,6 +554,8 @@ func BenchmarkStructComplexFailure(b *testing.B) { func BenchmarkStructComplexSuccessParallel(b *testing.B) { + validate := New() + tSuccess := &TestString{ Required: "Required", Len: "length==10", @@ -483,6 +583,8 @@ func BenchmarkStructComplexSuccessParallel(b *testing.B) { }, } + b.ReportAllocs() + b.RunParallel(func(pb *testing.PB) { for pb.Next() { validate.Struct(tSuccess) @@ -492,6 +594,8 @@ func BenchmarkStructComplexSuccessParallel(b *testing.B) { func BenchmarkStructComplexFailureParallel(b *testing.B) { + validate := New() + tFail := &TestString{ Required: "", Len: "", @@ -516,6 +620,8 @@ func BenchmarkStructComplexFailureParallel(b *testing.B) { }, } + b.ReportAllocs() + b.RunParallel(func(pb *testing.PB) { for pb.Next() { validate.Struct(tFail) diff --git a/cache.go b/cache.go index 76670c1..7534ea7 100644 --- a/cache.go +++ b/cache.go @@ -2,6 +2,7 @@ package validator import ( "fmt" + "log" "reflect" "strings" "sync" @@ -20,6 +21,15 @@ const ( typeExists ) +const ( + invalidValidation = "Invalid validation tag on field %s" + undefinedValidation = "Undefined validation function on field %s" +) + +// var ( +// validatable = reflect.ValueOf((*Validatable)(nil)).Elem() +// ) + type structCache struct { lock sync.Mutex m atomic.Value // map[reflect.Type]*cStruct @@ -105,6 +115,15 @@ func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStr cs = &cStruct{Name: sName, fields: make(map[int]*cField), fn: v.structLevelFuncs[typ]} + if vable, ok := reflect.PtrTo(typ).(Validatable); ok { + + if cs.fn != nil { + log.Println("warning: struct level validation overriding 'Validatabe' interface function") + } else { + cs.fn = vable.Validate + } + } + numFields := current.NumField() var ctag *cTag @@ -116,7 +135,7 @@ func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStr fld = typ.Field(i) - if !fld.Anonymous && fld.PkgPath != blank { + if !fld.Anonymous && len(fld.PkgPath) > 0 { continue } @@ -128,12 +147,11 @@ func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStr customName = fld.Name - if v.fieldNameTag != blank { + if v.hasTagNameFunc { - name := strings.SplitN(fld.Tag.Get(v.fieldNameTag), ",", 2)[0] + name := v.tagNameFunc(fld) - // dash check is for json "-" (aka skipValidationTag) means don't output in json - if name != "" && name != skipValidationTag { + if len(name) > 0 { customName = name } } @@ -142,7 +160,7 @@ func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStr // and so only struct level caching can be used instead of combined with Field tag caching if len(tag) > 0 { - ctag, _ = v.parseFieldTagsRecursive(tag, fld.Name, blank, false) + ctag, _ = v.parseFieldTagsRecursive(tag, fld.Name, "", false) } else { // even if field doesn't have validations need cTag for traversing to potential inner/nested // elements of the field. @@ -172,20 +190,18 @@ func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string, alias s alias = t } - if v.hasAliasValidators { - // check map for alias and process new tags, otherwise process as usual - if tagsVal, found := v.aliasValidators[t]; found { - - if i == 0 { - firstCtag, current = v.parseFieldTagsRecursive(tagsVal, fieldName, t, true) - } else { - next, curr := v.parseFieldTagsRecursive(tagsVal, fieldName, t, true) - current.next, current = next, curr + // check map for alias and process new tags, otherwise process as usual + if tagsVal, found := v.aliases[t]; found { - } + if i == 0 { + firstCtag, current = v.parseFieldTagsRecursive(tagsVal, fieldName, t, true) + } else { + next, curr := v.parseFieldTagsRecursive(tagsVal, fieldName, t, true) + current.next, current = next, curr - continue } + + continue } if i == 0 { @@ -214,10 +230,6 @@ func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string, alias s current.typeof = typeNoStructLevel continue - case existsTag: - current.typeof = typeExists - continue - default: // if a pipe character is needed within the param you must use the utf8Pipe representation "0x7C" @@ -244,7 +256,7 @@ func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string, alias s panic(strings.TrimSpace(fmt.Sprintf(invalidValidation, fieldName))) } - if current.fn, ok = v.validationFuncs[current.tag]; !ok { + if current.fn, ok = v.validations[current.tag]; !ok { panic(strings.TrimSpace(fmt.Sprintf(undefinedValidation, fieldName))) } diff --git a/doc.go b/doc.go index fdede2c..e44356d 100644 --- a/doc.go +++ b/doc.go @@ -192,17 +192,6 @@ Same as structonly tag except that any struct level validations will not run. Usage: nostructlevel -Exists - -Is a special tag without a validation function attached. It is used when a field -is a Pointer, Interface or Invalid and you wish to validate that it exists. -Example: want to ensure a bool exists if you define the bool as a pointer and -use exists it will ensure there is a value; couldn't use required as it would -fail when the bool was false. exists will fail is the value is a Pointer, Interface -or Invalid and is nil. - - Usage: exists - Omit Empty Allows conditional validation, for example if a field is not set with diff --git a/errors.go b/errors.go new file mode 100644 index 0000000..ce46333 --- /dev/null +++ b/errors.go @@ -0,0 +1,202 @@ +package validator + +import ( + "bytes" + "fmt" + "reflect" + "strings" +) + +const ( + fieldErrMsg = "Key: '%s' Error:Field validation for '%s' failed on the '%s' tag" +) + +// InvalidValidationError describes an invalid argument passed to +// `Struct`, `StructExcept`, StructPartial` or `Field` +type InvalidValidationError struct { + Type reflect.Type +} + +// Error returns InvalidValidationError message +func (e *InvalidValidationError) Error() string { + + if e.Type == nil { + return "validator: (nil)" + } + + return "validator: (nil " + e.Type.String() + ")" +} + +// ValidationErrors is an array of FieldError's +// for use in custom error messages post validation. +type ValidationErrors []FieldError + +// Error is intended for use in development + debugging and not intended to be a production error message. +// It allows ValidationErrors to subscribe to the Error interface. +// All information to create an error message specific to your application is contained within +// the FieldError found within the ValidationErrors array +func (ve ValidationErrors) Error() string { + + buff := bytes.NewBufferString("") + + var err *fieldError + + for i := 0; i < len(ve); i++ { + + err = ve[i].(*fieldError) + buff.WriteString(err.Error()) + buff.WriteString("\n") + } + + return strings.TrimSpace(buff.String()) +} + +// FieldError contains all functions to get error details +type FieldError interface { + + // returns the validation tag that failed. if the + // validation was an alias, this will return the + // alias name and not the underlying tag that failed. + // + // eg. alias "iscolor": "hexcolor|rgb|rgba|hsl|hsla" + // will return "iscolor" + Tag() string + + // returns the validation tag that failed, even if an + // alias the actual tag within the alias will be returned. + // If an 'or' validation fails the entire or will be returned. + // + // eg. alias "iscolor": "hexcolor|rgb|rgba|hsl|hsla" + // will return "hexcolor|rgb|rgba|hsl|hsla" + ActualTag() string + + // returns the namespace for the field error, with the tag + // name taking precedence over the fields actual name. + // + // eq. JSON name "User.fname" see ActualNamespace for comparison + // + // NOTE: this field can be blank when validating a single primitive field + // using validate.Field(...) as there is no way to extract it's name + Namespace() string + + // returns the namespace for the field error, with the fields + // actual name. + // + // eq. "User.FirstName" see Namespace for comparison + // + // NOTE: this field can be blank when validating a single primitive field + // using validate.Field(...) as there is no way to extract it's name + ActualNamespace() string + + // returns the fields name with the tag name taking precedence over the + // fields actual name. + // + // eq. JSON name "fname" + // see ActualField for comparison + Field() string + + // returns the fields actual name. + // + // eq. "FirstName" + // see Field for comparison + ActualField() string + + // returns the actual fields value in case needed for creating the error + // message + Value() interface{} + + // returns the param value, already converted into the fields type for + // comparison; this will also help with generating an error message + Param() interface{} + + // Kind returns the Field's reflect Kind + // + // eg. time.Time's kind is a struct + Kind() reflect.Kind + + // Type returns the Field's reflect Type + // + // // eg. time.Time's type is time.Time + Type() reflect.Type +} + +// compile time interface checks +var _ FieldError = new(fieldError) +var _ error = new(fieldError) + +// fieldError contains a single field's validation error along +// with other properties that may be needed for error message creation +// it complies with the FieldError interface +type fieldError struct { + tag string + actualTag string + ns string + actualNs string + field string + actualField string + value interface{} + param interface{} + kind reflect.Kind + typ reflect.Type +} + +// Tag returns the validation tag that failed. +func (fe *fieldError) Tag() string { + return fe.tag +} + +// ActualTag returns the validation tag that failed, even if an +// alias the actual tag within the alias will be returned. +func (fe *fieldError) ActualTag() string { + return fe.actualTag +} + +// Namespace returns the namespace for the field error, with the tag +// name taking precedence over the fields actual name. +func (fe *fieldError) Namespace() string { + return fe.ns +} + +// ActualNamespace returns the namespace for the field error, with the fields +// actual name. +func (fe *fieldError) ActualNamespace() string { + return fe.actualNs +} + +// Field returns the fields name with the tag name taking precedence over the +// fields actual name. +func (fe *fieldError) Field() string { + return fe.field +} + +// ActualField returns the fields actual name. +func (fe *fieldError) ActualField() string { + return fe.actualField +} + +// Value returns the actual fields value in case needed for creating the error +// message +func (fe *fieldError) Value() interface{} { + return fe.value +} + +// Param returns the param value, already converted into the fields type for +// comparison; this will also help with generating an error message +func (fe *fieldError) Param() interface{} { + return fe.param +} + +// Kind returns the Field's reflect Kind +func (fe *fieldError) Kind() reflect.Kind { + return fe.kind +} + +// Type returns the Field's reflect Type +func (fe *fieldError) Type() reflect.Type { + return fe.typ +} + +// Error returns the fieldError's error message +func (fe *fieldError) Error() string { + return fmt.Sprintf(fieldErrMsg, fe.ns, fe.field, fe.tag) +} diff --git a/examples_test.go b/examples_test.go index fde2246..3f4df7e 100644 --- a/examples_test.go +++ b/examples_test.go @@ -1,83 +1,83 @@ package validator_test -import ( - "fmt" - - "gopkg.in/go-playground/validator.v8" -) - -func ExampleValidate_new() { - config := &validator.Config{TagName: "validate"} - - validator.New(config) -} - -func ExampleValidate_field() { - // This should be stored somewhere globally - var validate *validator.Validate - - config := &validator.Config{TagName: "validate"} - - validate = validator.New(config) - - i := 0 - errs := validate.Field(i, "gt=1,lte=10") - err := errs.(validator.ValidationErrors)[""] - fmt.Println(err.Field) - fmt.Println(err.Tag) - fmt.Println(err.Kind) // NOTE: Kind and Type can be different i.e. time Kind=struct and Type=time.Time - fmt.Println(err.Type) - fmt.Println(err.Param) - fmt.Println(err.Value) - //Output: - // - //gt - //int - //int - //1 - //0 -} - -func ExampleValidate_struct() { - // This should be stored somewhere globally - var validate *validator.Validate - - config := &validator.Config{TagName: "validate"} - - validate = validator.New(config) - - type ContactInformation struct { - Phone string `validate:"required"` - Street string `validate:"required"` - City string `validate:"required"` - } - - type User struct { - Name string `validate:"required,excludesall=!@#$%^&*()_+-=:;?/0x2C"` // 0x2C = comma (,) - Age int8 `validate:"required,gt=0,lt=150"` - Email string `validate:"email"` - ContactInformation []*ContactInformation - } - - contactInfo := &ContactInformation{ - Street: "26 Here Blvd.", - City: "Paradeso", - } - - user := &User{ - Name: "Joey Bloggs", - Age: 31, - Email: "joeybloggs@gmail.com", - ContactInformation: []*ContactInformation{contactInfo}, - } - - errs := validate.Struct(user) - for _, v := range errs.(validator.ValidationErrors) { - fmt.Println(v.Field) // Phone - fmt.Println(v.Tag) // required - //... and so forth - //Output: - //Phone - //required - } -} +// import ( +// "fmt" + +// "gopkg.in/go-playground/validator.v8" +// ) + +// func ExampleValidate_new() { +// config := &validator.Config{TagName: "validate"} + +// validator.New(config) +// } + +// func ExampleValidate_field() { +// // This should be stored somewhere globally +// var validate *validator.Validate + +// config := &validator.Config{TagName: "validate"} + +// validate = validator.New(config) + +// i := 0 +// errs := validate.Field(i, "gt=1,lte=10") +// err := errs.(validator.ValidationErrors)[""] +// fmt.Println(err.Field) +// fmt.Println(err.Tag) +// fmt.Println(err.Kind) // NOTE: Kind and Type can be different i.e. time Kind=struct and Type=time.Time +// fmt.Println(err.Type) +// fmt.Println(err.Param) +// fmt.Println(err.Value) +// //Output: +// // +// //gt +// //int +// //int +// //1 +// //0 +// } + +// func ExampleValidate_struct() { +// // This should be stored somewhere globally +// var validate *validator.Validate + +// config := &validator.Config{TagName: "validate"} + +// validate = validator.New(config) + +// type ContactInformation struct { +// Phone string `validate:"required"` +// Street string `validate:"required"` +// City string `validate:"required"` +// } + +// type User struct { +// Name string `validate:"required,excludesall=!@#$%^&*()_+-=:;?/0x2C"` // 0x2C = comma (,) +// Age int8 `validate:"required,gt=0,lt=150"` +// Email string `validate:"email"` +// ContactInformation []*ContactInformation +// } + +// contactInfo := &ContactInformation{ +// Street: "26 Here Blvd.", +// City: "Paradeso", +// } + +// user := &User{ +// Name: "Joey Bloggs", +// Age: 31, +// Email: "joeybloggs@gmail.com", +// ContactInformation: []*ContactInformation{contactInfo}, +// } + +// errs := validate.Struct(user) +// for _, v := range errs.(validator.ValidationErrors) { +// fmt.Println(v.Field) // Phone +// fmt.Println(v.Tag) // required +// //... and so forth +// //Output: +// //Phone +// //required +// } +// } diff --git a/field_level.go b/field_level.go new file mode 100644 index 0000000..4ffb5f3 --- /dev/null +++ b/field_level.go @@ -0,0 +1,50 @@ +package validator + +import "reflect" + +// FieldLevel contains all the information and helper functions +// to validate a field +type FieldLevel interface { + + // returns the top level struct, if any + Top() reflect.Value + + // returns the current fields parent struct, if any + Parent() reflect.Value + + // returns current field for validation + Field() reflect.Value + + // returns param for validation against current field + Param() string + + // ExtractType gets the actual underlying type of field value. + // It will dive into pointers, customTypes and return you the + // underlying value and it's kind. + ExtractType(field reflect.Value) (value reflect.Value, kind reflect.Kind, nullable bool) + + // traverses the parent struct to retrieve a specific field denoted by the provided namespace + // in the param and returns the field, field kind and whether is was successful in retrieving + // the field at all. + // + // NOTE: when not successful ok will be false, this can happen when a nested struct is nil and so the field + // could not be retrieved because it didn't exist. + GetStructFieldOK() (reflect.Value, reflect.Kind, bool) +} + +var _ FieldLevel = new(validate) + +// Field returns current field for validation +func (v *validate) Field() reflect.Value { + return v.flField +} + +// Param returns param for validation against current field +func (v *validate) Param() string { + return v.flParam +} + +// GetStructFieldOK returns Param returns param for validation against current field +func (v *validate) GetStructFieldOK() (reflect.Value, reflect.Kind, bool) { + return v.getStructFieldOKInternal(v.slflParent, v.flParam) +} diff --git a/struct_level.go b/struct_level.go new file mode 100644 index 0000000..33bfd59 --- /dev/null +++ b/struct_level.go @@ -0,0 +1,166 @@ +package validator + +import "reflect" + +// StructLevelFunc accepts all values needed for struct level validation +type StructLevelFunc func(sl StructLevel) + +// StructLevel contains all the information and helper functions +// to validate a struct +type StructLevel interface { + + // returns the main validation object, in case one want to call validations internally. + Validator() *Validate + + // returns the top level struct, if any + Top() reflect.Value + + // returns the current fields parent struct, if any + Parent() reflect.Value + + // returns the current struct. + // this is not needed when implementing 'Validatable' interface, + // only when a StructLevel is registered + Current() reflect.Value + + // ExtractType gets the actual underlying type of field value. + // It will dive into pointers, customTypes and return you the + // underlying value and it's kind. + ExtractType(field reflect.Value) (value reflect.Value, kind reflect.Kind, nullable bool) + + // reports an error just by passing the field and tag information + // + // NOTES: + // + // fieldName and altName get appended to the existing namespace that + // validator is on. eg. pass 'FirstName' or 'Names[0]' depending + // on the nesting + // + // tag can be an existing validation tag or just something you make up + // and process on the flip side it's up to you. + ReportError(field interface{}, fieldName, altName, tag string) + + // reports an error just by passing ValidationErrors + // + // NOTES: + // + // relativeNamespace and relativeActualNamespace get appended to the + // existing namespace that validator is on. + // eg. pass 'User.FirstName' or 'Users[0].FirstName' depending + // on the nesting. most of the time they will be blank, unless you validate + // at a level lower the the current field depth + // + // tag can be an existing validation tag or just something you make up + // and process on the flip side it's up to you. + ReportValidationErrors(relativeNamespace, relativeActualNamespace string, errs ValidationErrors) +} + +var _ StructLevel = new(validate) + +// Top returns the top level struct +// +// NOTE: this can be the same as the current struct being validated +// if not is a nested struct. +// +// this is only called when within Struct and Field Level validation and +// should not be relied upon for an acurate value otherwise. +func (v *validate) Top() reflect.Value { + return v.top +} + +// Parent returns the current structs parent +// +// NOTE: this can be the same as the current struct being validated +// if not is a nested struct. +// +// this is only called when within Struct and Field Level validation and +// should not be relied upon for an acurate value otherwise. +func (v *validate) Parent() reflect.Value { + return v.slflParent +} + +// Current returns the current struct. +func (v *validate) Current() reflect.Value { + return v.slCurrent +} + +// Validator returns the main validation object, in case one want to call validations internally. +func (v *validate) Validator() *Validate { + return v.v +} + +// ExtractType gets the actual underlying type of field value. +func (v *validate) ExtractType(field reflect.Value) (reflect.Value, reflect.Kind, bool) { + return v.extractTypeInternal(field, false) +} + +// ReportError reports an error just by passing the field and tag information +func (v *validate) ReportError(field interface{}, fieldName, altName, tag string) { + + fv, kind, _ := v.extractTypeInternal(reflect.ValueOf(field), false) + + if len(altName) == 0 { + altName = fieldName + } + + ns := append(v.slNs, fieldName...) + nsActual := append(v.slActualNs, altName...) + + switch kind { + case reflect.Invalid: + + v.errs = append(v.errs, + &fieldError{ + tag: tag, + actualTag: tag, + ns: string(ns), + actualNs: string(nsActual), + field: fieldName, + actualField: altName, + param: "", + kind: kind, + }, + ) + + default: + + v.errs = append(v.errs, + &fieldError{ + tag: tag, + actualTag: tag, + ns: string(ns), + actualNs: string(nsActual), + field: fieldName, + actualField: altName, + value: fv.Interface(), + param: "", + kind: kind, + typ: fv.Type(), + }, + ) + } +} + +// ReportValidationErrors reports ValidationErrors obtained from running validations within the Struct Level validation. +// +// NOTE: this function prepends the current namespace to the relative ones. +func (v *validate) ReportValidationErrors(relativeNamespace, relativeActualNamespace string, errs ValidationErrors) { + + var err *fieldError + + for i := 0; i < len(errs); i++ { + + err = errs[i].(*fieldError) + err.ns = string(append(append(v.slNs, err.ns...), err.field...)) + err.actualNs = string(append(append(v.slActualNs, err.actualNs...), err.actualField...)) + + v.errs = append(v.errs, err) + } +} + +// Validatable is the interface a struct can implement and +// be validated just like registering a StructLevel validation +// (they actually have the exact same signature.) +type Validatable interface { + Validate(sl StructLevel) +} diff --git a/util.go b/util.go index e811579..ee9874e 100644 --- a/util.go +++ b/util.go @@ -6,41 +6,26 @@ import ( "strings" ) -const ( - blank = "" - namespaceSeparator = "." - leftBracket = "[" - rightBracket = "]" - restrictedTagChars = ".[],|=+()`~!@#$%^&*\\\"/?<>{}" - restrictedAliasErr = "Alias '%s' either contains restricted characters or is the same as a restricted tag needed for normal operation" - restrictedTagErr = "Tag '%s' either contains restricted characters or is the same as a restricted tag needed for normal operation" -) - -var ( - restrictedTags = map[string]struct{}{ - diveTag: {}, - existsTag: {}, - structOnlyTag: {}, - omitempty: {}, - skipValidationTag: {}, - utf8HexComma: {}, - utf8Pipe: {}, - noStructLevelTag: {}, - } -) - -// ExtractType gets the actual underlying type of field value. +// import ( +// "reflect" +// "strconv" +// "strings" +// ) + +// const ( +// blank = "" +// namespaceSeparator = "." +// leftBracket = "[" +// rightBracket = "]" +// restrictedTagChars = ".[],|=+()`~!@#$%^&*\\\"/?<>{}" +// restrictedAliasErr = "Alias '%s' either contains restricted characters or is the same as a restricted tag needed for normal operation" +// restrictedTagErr = "Tag '%s' either contains restricted characters or is the same as a restricted tag needed for normal operation" +// ) + +// extractTypeInternal gets the actual underlying type of field value. // It will dive into pointers, customTypes and return you the // underlying value and it's kind. -// it is exposed for use within you Custom Functions -func (v *Validate) ExtractType(current reflect.Value) (reflect.Value, reflect.Kind) { - - val, k, _ := v.extractTypeInternal(current, false) - return val, k -} - -// only exists to not break backward compatibility, needed to return the third param for a bug fix internally -func (v *Validate) extractTypeInternal(current reflect.Value, nullable bool) (reflect.Value, reflect.Kind, bool) { +func (v *validate) extractTypeInternal(current reflect.Value, nullable bool) (reflect.Value, reflect.Kind, bool) { switch current.Kind() { case reflect.Ptr: @@ -68,9 +53,9 @@ func (v *Validate) extractTypeInternal(current reflect.Value, nullable bool) (re default: - if v.hasCustomFuncs { + if v.v.hasCustomFuncs { - if fn, ok := v.customTypeFuncs[current.Type()]; ok { + if fn, ok := v.v.customFuncs[current.Type()]; ok { return v.extractTypeInternal(reflect.ValueOf(fn(current)), nullable) } } @@ -79,19 +64,20 @@ func (v *Validate) extractTypeInternal(current reflect.Value, nullable bool) (re } } -// GetStructFieldOK traverses a struct to retrieve a specific field denoted by the provided namespace and +// getStructFieldOKInternal traverses a struct to retrieve a specific field denoted by the provided namespace and // returns the field, field kind and whether is was successful in retrieving the field at all. +// // NOTE: when not successful ok will be false, this can happen when a nested struct is nil and so the field // could not be retrieved because it didn't exist. -func (v *Validate) GetStructFieldOK(current reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool) { +func (v *validate) getStructFieldOKInternal(current reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool) { - current, kind := v.ExtractType(current) + current, kind, _ := v.ExtractType(current) if kind == reflect.Invalid { return current, kind, false } - if namespace == blank { + if namespace == "" { return current, kind, true } @@ -107,7 +93,7 @@ func (v *Validate) GetStructFieldOK(current reflect.Value, namespace string) (re fld := namespace ns := namespace - if typ != timeType && typ != timePtrType { + if typ != timeType { idx := strings.Index(namespace, namespaceSeparator) @@ -115,7 +101,7 @@ func (v *Validate) GetStructFieldOK(current reflect.Value, namespace string) (re fld = namespace[:idx] ns = namespace[idx+1:] } else { - ns = blank + ns = "" } bracketIdx := strings.Index(fld, leftBracket) @@ -127,7 +113,7 @@ func (v *Validate) GetStructFieldOK(current reflect.Value, namespace string) (re current = current.FieldByName(fld) - return v.GetStructFieldOK(current, ns) + return v.getStructFieldOKInternal(current, ns) } case reflect.Array, reflect.Slice: @@ -148,7 +134,7 @@ func (v *Validate) GetStructFieldOK(current reflect.Value, namespace string) (re } } - return v.GetStructFieldOK(current.Index(arrIdx), namespace[startIdx:]) + return v.getStructFieldOKInternal(current.Index(arrIdx), namespace[startIdx:]) case reflect.Map: idx := strings.Index(namespace, leftBracket) + 1 @@ -167,47 +153,47 @@ func (v *Validate) GetStructFieldOK(current reflect.Value, namespace string) (re switch current.Type().Key().Kind() { case reflect.Int: i, _ := strconv.Atoi(key) - return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(i)), namespace[endIdx+1:]) + return v.getStructFieldOKInternal(current.MapIndex(reflect.ValueOf(i)), namespace[endIdx+1:]) case reflect.Int8: i, _ := strconv.ParseInt(key, 10, 8) - return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(int8(i))), namespace[endIdx+1:]) + return v.getStructFieldOKInternal(current.MapIndex(reflect.ValueOf(int8(i))), namespace[endIdx+1:]) case reflect.Int16: i, _ := strconv.ParseInt(key, 10, 16) - return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(int16(i))), namespace[endIdx+1:]) + return v.getStructFieldOKInternal(current.MapIndex(reflect.ValueOf(int16(i))), namespace[endIdx+1:]) case reflect.Int32: i, _ := strconv.ParseInt(key, 10, 32) - return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(int32(i))), namespace[endIdx+1:]) + return v.getStructFieldOKInternal(current.MapIndex(reflect.ValueOf(int32(i))), namespace[endIdx+1:]) case reflect.Int64: i, _ := strconv.ParseInt(key, 10, 64) - return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(i)), namespace[endIdx+1:]) + return v.getStructFieldOKInternal(current.MapIndex(reflect.ValueOf(i)), namespace[endIdx+1:]) case reflect.Uint: i, _ := strconv.ParseUint(key, 10, 0) - return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(uint(i))), namespace[endIdx+1:]) + return v.getStructFieldOKInternal(current.MapIndex(reflect.ValueOf(uint(i))), namespace[endIdx+1:]) case reflect.Uint8: i, _ := strconv.ParseUint(key, 10, 8) - return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(uint8(i))), namespace[endIdx+1:]) + return v.getStructFieldOKInternal(current.MapIndex(reflect.ValueOf(uint8(i))), namespace[endIdx+1:]) case reflect.Uint16: i, _ := strconv.ParseUint(key, 10, 16) - return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(uint16(i))), namespace[endIdx+1:]) + return v.getStructFieldOKInternal(current.MapIndex(reflect.ValueOf(uint16(i))), namespace[endIdx+1:]) case reflect.Uint32: i, _ := strconv.ParseUint(key, 10, 32) - return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(uint32(i))), namespace[endIdx+1:]) + return v.getStructFieldOKInternal(current.MapIndex(reflect.ValueOf(uint32(i))), namespace[endIdx+1:]) case reflect.Uint64: i, _ := strconv.ParseUint(key, 10, 64) - return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(i)), namespace[endIdx+1:]) + return v.getStructFieldOKInternal(current.MapIndex(reflect.ValueOf(i)), namespace[endIdx+1:]) case reflect.Float32: f, _ := strconv.ParseFloat(key, 32) - return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(float32(f))), namespace[endIdx+1:]) + return v.getStructFieldOKInternal(current.MapIndex(reflect.ValueOf(float32(f))), namespace[endIdx+1:]) case reflect.Float64: f, _ := strconv.ParseFloat(key, 64) - return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(f)), namespace[endIdx+1:]) + return v.getStructFieldOKInternal(current.MapIndex(reflect.ValueOf(f)), namespace[endIdx+1:]) case reflect.Bool: b, _ := strconv.ParseBool(key) - return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(b)), namespace[endIdx+1:]) + return v.getStructFieldOKInternal(current.MapIndex(reflect.ValueOf(b)), namespace[endIdx+1:]) // reflect.Type = string default: - return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(key)), namespace[endIdx+1:]) + return v.getStructFieldOKInternal(current.MapIndex(reflect.ValueOf(key)), namespace[endIdx+1:]) } } diff --git a/validator.go b/validator.go index 2b1d716..dec2bd3 100644 --- a/validator.go +++ b/validator.go @@ -1,580 +1,95 @@ -/** - * Package validator - * - * MISC: - * - anonymous structs - they don't have names so expect the Struct name within StructErrors to be blank - * - */ - package validator import ( - "bytes" - "errors" "fmt" "reflect" - "strings" - "sync" - "time" ) const ( - utf8HexComma = "0x2C" - utf8Pipe = "0x7C" - tagSeparator = "," - orSeparator = "|" - tagKeySeparator = "=" - structOnlyTag = "structonly" - noStructLevelTag = "nostructlevel" - omitempty = "omitempty" - skipValidationTag = "-" - diveTag = "dive" - existsTag = "exists" - fieldErrMsg = "Key: '%s' Error:Field validation for '%s' failed on the '%s' tag" - arrayIndexFieldName = "%s" + leftBracket + "%d" + rightBracket - mapIndexFieldName = "%s" + leftBracket + "%v" + rightBracket - invalidValidation = "Invalid validation tag on field %s" - undefinedValidation = "Undefined validation function on field %s" - validatorNotInitialized = "Validator instance not initialized" - fieldNameRequired = "Field Name Required" - tagRequired = "Tag Required" -) - -var ( - timeType = reflect.TypeOf(time.Time{}) - timePtrType = reflect.TypeOf(&time.Time{}) - defaultCField = new(cField) + arrayIndexFieldName = "%s" + leftBracket + "%d" + rightBracket + mapIndexFieldName = "%s" + leftBracket + "%v" + rightBracket ) -// StructLevel contains all of the information and helper methods -// for reporting errors during struct level validation -type StructLevel struct { - TopStruct reflect.Value - CurrentStruct reflect.Value - errPrefix string - nsPrefix string - errs ValidationErrors - v *Validate -} - -// ReportValidationErrors accepts the key relative to the top level struct and validatin errors. -// Example: had a triple nested struct User, ContactInfo, Country and ran errs := validate.Struct(country) -// from within a User struct level validation would call this method like so: -// ReportValidationErrors("ContactInfo.", errs) -// NOTE: relativeKey can contain both the Field Relative and Custom name relative paths -// i.e. ReportValidationErrors("ContactInfo.|cInfo", errs) where cInfo represents say the JSON name of -// the relative path; this will be split into 2 variables in the next valiator version. -func (sl *StructLevel) ReportValidationErrors(relativeKey string, errs ValidationErrors) { - for _, e := range errs { - - idx := strings.Index(relativeKey, "|") - var rel string - var cRel string - - if idx != -1 { - rel = relativeKey[:idx] - cRel = relativeKey[idx+1:] - } else { - rel = relativeKey - } - - key := sl.errPrefix + rel + e.Field - - e.FieldNamespace = key - e.NameNamespace = sl.nsPrefix + cRel + e.Name - - sl.errs[key] = e - } -} - -// ReportError reports an error just by passing the field and tag information -// NOTE: tag can be an existing validation tag or just something you make up -// and precess on the flip side it's up to you. -func (sl *StructLevel) ReportError(field reflect.Value, fieldName string, customName string, tag string) { - - field, kind := sl.v.ExtractType(field) - - if fieldName == blank { - panic(fieldNameRequired) - } - - if customName == blank { - customName = fieldName - } - - if tag == blank { - panic(tagRequired) - } - - ns := sl.errPrefix + fieldName - - switch kind { - case reflect.Invalid: - sl.errs[ns] = &FieldError{ - FieldNamespace: ns, - NameNamespace: sl.nsPrefix + customName, - Name: customName, - Field: fieldName, - Tag: tag, - ActualTag: tag, - Param: blank, - Kind: kind, - } - default: - sl.errs[ns] = &FieldError{ - FieldNamespace: ns, - NameNamespace: sl.nsPrefix + customName, - Name: customName, - Field: fieldName, - Tag: tag, - ActualTag: tag, - Param: blank, - Value: field.Interface(), - Kind: kind, - Type: field.Type(), - } - } -} - -// Validate contains the validator settings passed in using the Config struct -type Validate struct { - tagName string - fieldNameTag string - validationFuncs map[string]Func - structLevelFuncs map[reflect.Type]StructLevelFunc - customTypeFuncs map[reflect.Type]CustomTypeFunc - aliasValidators map[string]string - hasCustomFuncs bool - hasAliasValidators bool - hasStructLevelFuncs bool - tagCache *tagCache - structCache *structCache - errsPool *sync.Pool -} - -func (v *Validate) initCheck() { - if v == nil { - panic(validatorNotInitialized) - } -} - -// Config contains the options that a Validator instance will use. -// It is passed to the New() function -type Config struct { - TagName string - FieldNameTag string -} - -// CustomTypeFunc allows for overriding or adding custom field type handler functions -// field = field value of the type to return a value to be validated -// example Valuer from sql drive see https://golang.org/src/database/sql/driver/types.go?s=1210:1293#L29 -type CustomTypeFunc func(field reflect.Value) interface{} - -// Func accepts all values needed for file and cross field validation -// v = validator instance, needed but some built in functions for it's custom types -// topStruct = top level struct when validating by struct otherwise nil -// currentStruct = current level struct when validating by struct otherwise optional comparison value -// field = field value for validation -// param = parameter used in validation i.e. gt=0 param would be 0 -type Func func(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldtype reflect.Type, fieldKind reflect.Kind, param string) bool - -// StructLevelFunc accepts all values needed for struct level validation -type StructLevelFunc func(v *Validate, structLevel *StructLevel) - -// ValidationErrors is a type of map[string]*FieldError -// it exists to allow for multiple errors to be passed from this library -// and yet still subscribe to the error interface -type ValidationErrors map[string]*FieldError - -// Error is intended for use in development + debugging and not intended to be a production error message. -// It allows ValidationErrors to subscribe to the Error interface. -// All information to create an error message specific to your application is contained within -// the FieldError found within the ValidationErrors map -func (ve ValidationErrors) Error() string { - - buff := bytes.NewBufferString(blank) - - for key, err := range ve { - buff.WriteString(fmt.Sprintf(fieldErrMsg, key, err.Field, err.Tag)) - buff.WriteString("\n") - } - - return strings.TrimSpace(buff.String()) -} - -// FieldError contains a single field's validation error along -// with other properties that may be needed for error message creation -type FieldError struct { - FieldNamespace string - NameNamespace string - Field string - Name string - Tag string - ActualTag string - Kind reflect.Kind - Type reflect.Type - Param string - Value interface{} -} - -// New creates a new Validate instance for use. -func New(config *Config) *Validate { - - tc := new(tagCache) - tc.m.Store(make(map[string]*cTag)) - - sc := new(structCache) - sc.m.Store(make(map[reflect.Type]*cStruct)) - - v := &Validate{ - tagName: config.TagName, - fieldNameTag: config.FieldNameTag, - tagCache: tc, - structCache: sc, - errsPool: &sync.Pool{New: func() interface{} { - return ValidationErrors{} - }}} - - if len(v.aliasValidators) == 0 { - // must copy alias validators for separate validations to be used in each validator instance - v.aliasValidators = map[string]string{} - for k, val := range bakedInAliasValidators { - v.RegisterAliasValidation(k, val) - } - } - - if len(v.validationFuncs) == 0 { - // must copy validators for separate validations to be used in each instance - v.validationFuncs = map[string]Func{} - for k, val := range bakedInValidators { - v.RegisterValidation(k, val) - } - } - - return v -} - -// RegisterStructValidation registers a StructLevelFunc against a number of types -// NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation -func (v *Validate) RegisterStructValidation(fn StructLevelFunc, types ...interface{}) { - v.initCheck() - - if v.structLevelFuncs == nil { - v.structLevelFuncs = map[reflect.Type]StructLevelFunc{} - } - - for _, t := range types { - v.structLevelFuncs[reflect.TypeOf(t)] = fn - } - - v.hasStructLevelFuncs = true -} - -// RegisterValidation adds a validation Func to a Validate's map of validators denoted by the key -// NOTE: if the key already exists, the previous validation function will be replaced. -// NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation -func (v *Validate) RegisterValidation(key string, fn Func) error { - v.initCheck() - - if key == blank { - return errors.New("Function Key cannot be empty") - } - - if fn == nil { - return errors.New("Function cannot be empty") - } - - _, ok := restrictedTags[key] - - if ok || strings.ContainsAny(key, restrictedTagChars) { - panic(fmt.Sprintf(restrictedTagErr, key)) - } - - v.validationFuncs[key] = fn - - return nil -} - -// RegisterCustomTypeFunc registers a CustomTypeFunc against a number of types -// NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation -func (v *Validate) RegisterCustomTypeFunc(fn CustomTypeFunc, types ...interface{}) { - v.initCheck() - - if v.customTypeFuncs == nil { - v.customTypeFuncs = map[reflect.Type]CustomTypeFunc{} - } - - for _, t := range types { - v.customTypeFuncs[reflect.TypeOf(t)] = fn - } - - v.hasCustomFuncs = true -} - -// RegisterAliasValidation registers a mapping of a single validationstag that -// defines a common or complex set of validation(s) to simplify adding validation -// to structs. NOTE: when returning an error the tag returned in FieldError will be -// the alias tag unless the dive tag is part of the alias; everything after the -// dive tag is not reported as the alias tag. Also the ActualTag in the before case -// will be the actual tag within the alias that failed. -// NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation -func (v *Validate) RegisterAliasValidation(alias, tags string) { - v.initCheck() - - _, ok := restrictedTags[alias] - - if ok || strings.ContainsAny(alias, restrictedTagChars) { - panic(fmt.Sprintf(restrictedAliasErr, alias)) - } - - v.aliasValidators[alias] = tags - v.hasAliasValidators = true -} - -// Field validates a single field using tag style validation and returns nil or ValidationErrors as type error. -// You will need to assert the error if it's not nil i.e. err.(validator.ValidationErrors) to access the map of errors. -// 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 -func (v *Validate) Field(field interface{}, tag string) error { - v.initCheck() - - if len(tag) == 0 || tag == skipValidationTag { - return nil - } - - errs := v.errsPool.Get().(ValidationErrors) - fieldVal := reflect.ValueOf(field) - - ctag, ok := v.tagCache.Get(tag) - if !ok { - v.tagCache.lock.Lock() - defer v.tagCache.lock.Unlock() - - // could have been multiple trying to access, but once first is done this ensures tag - // isn't parsed again. - ctag, ok = v.tagCache.Get(tag) - if !ok { - ctag, _ = v.parseFieldTagsRecursive(tag, blank, blank, false) - v.tagCache.Set(tag, ctag) - } - } - - v.traverseField(fieldVal, fieldVal, fieldVal, blank, blank, errs, false, false, nil, nil, defaultCField, ctag) - - if len(errs) == 0 { - v.errsPool.Put(errs) - return nil - } - - return errs +// per validate contruct +type validate struct { + v *Validate + top reflect.Value + ns []byte + actualNs []byte + errs ValidationErrors + isPartial bool + hasExcludes bool + includeExclude map[string]struct{} // reset only if StructPartial or StructExcept are called, no need otherwise + + // StructLevel & FieldLevel fields + slflParent reflect.Value + slCurrent reflect.Value + slNs []byte + slActualNs []byte + flField reflect.Value + flParam string } -// FieldWithValue validates a single field, against another fields value using tag style validation and returns nil or ValidationErrors. -// You will need to assert the error if it's not nil i.e. err.(validator.ValidationErrors) to access the map of errors. -// 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 -func (v *Validate) FieldWithValue(val interface{}, field interface{}, tag string) error { - v.initCheck() +// parent and current will be the same the first run of validateStruct +func (v *validate) validateStruct(parent reflect.Value, current reflect.Value, typ reflect.Type, ns []byte, actualNs []byte, ct *cTag) { - if len(tag) == 0 || tag == skipValidationTag { - return nil - } + first := len(ns) == 0 - errs := v.errsPool.Get().(ValidationErrors) - topVal := reflect.ValueOf(val) - - ctag, ok := v.tagCache.Get(tag) + cs, ok := v.v.structCache.Get(typ) if !ok { - v.tagCache.lock.Lock() - defer v.tagCache.lock.Unlock() - - // could have been multiple trying to access, but once first is done this ensures tag - // isn't parsed again. - ctag, ok = v.tagCache.Get(tag) - if !ok { - ctag, _ = v.parseFieldTagsRecursive(tag, blank, blank, false) - v.tagCache.Set(tag, ctag) - } - } - - v.traverseField(topVal, topVal, reflect.ValueOf(field), blank, blank, errs, false, false, nil, nil, defaultCField, ctag) - - if len(errs) == 0 { - v.errsPool.Put(errs) - return nil + cs = v.v.extractStructCache(current, typ.Name()) } - return errs -} - -// StructPartial validates the fields passed in only, ignoring all others. -// Fields may be provided in a namespaced fashion relative to the struct provided -// i.e. NestedStruct.Field or NestedArrayField[0].Struct.Name and returns nil or ValidationErrors as error -// You will need to assert the error if it's not nil i.e. err.(validator.ValidationErrors) to access the map of errors. -func (v *Validate) StructPartial(current interface{}, fields ...string) error { - v.initCheck() - - sv, _ := v.ExtractType(reflect.ValueOf(current)) - name := sv.Type().Name() - m := map[string]struct{}{} - - if fields != nil { - for _, k := range fields { - - flds := strings.Split(k, namespaceSeparator) - if len(flds) > 0 { - - key := name + namespaceSeparator - for _, s := range flds { + if first { - idx := strings.Index(s, leftBracket) + ns = append(ns, cs.Name...) + ns = append(ns, '.') - if idx != -1 { - for idx != -1 { - key += s[:idx] - m[key] = struct{}{} - - idx2 := strings.Index(s, rightBracket) - idx2++ - key += s[idx:idx2] - m[key] = struct{}{} - s = s[idx2:] - idx = strings.Index(s, leftBracket) - } - } else { - - key += s - m[key] = struct{}{} - } - - key += namespaceSeparator - } - } - } + actualNs = append(actualNs, cs.Name...) + actualNs = append(actualNs, '.') } - errs := v.errsPool.Get().(ValidationErrors) - - v.ensureValidStruct(sv, sv, sv, blank, blank, errs, true, len(m) != 0, false, m, false) - - if len(errs) == 0 { - v.errsPool.Put(errs) - return nil - } - - return errs -} - -// StructExcept validates all fields except the ones passed in. -// Fields may be provided in a namespaced fashion relative to the struct provided -// i.e. NestedStruct.Field or NestedArrayField[0].Struct.Name and returns nil or ValidationErrors as error -// You will need to assert the error if it's not nil i.e. err.(validator.ValidationErrors) to access the map of errors. -func (v *Validate) StructExcept(current interface{}, fields ...string) error { - v.initCheck() - - sv, _ := v.ExtractType(reflect.ValueOf(current)) - name := sv.Type().Name() - m := map[string]struct{}{} - - for _, key := range fields { - m[name+namespaceSeparator+key] = struct{}{} - } - - errs := v.errsPool.Get().(ValidationErrors) - - v.ensureValidStruct(sv, sv, sv, blank, blank, errs, true, len(m) != 0, true, m, false) - - if len(errs) == 0 { - v.errsPool.Put(errs) - return nil - } - - return errs -} - -// Struct validates a structs exposed fields, and automatically validates nested structs, unless otherwise specified. -// it returns nil or ValidationErrors as error. -// You will need to assert the error if it's not nil i.e. err.(validator.ValidationErrors) to access the map of errors. -func (v *Validate) Struct(current interface{}) error { - v.initCheck() - - errs := v.errsPool.Get().(ValidationErrors) - sv := reflect.ValueOf(current) - - v.ensureValidStruct(sv, sv, sv, blank, blank, errs, true, false, false, nil, false) - - if len(errs) == 0 { - v.errsPool.Put(errs) - return nil - } - - return errs -} - -func (v *Validate) ensureValidStruct(topStruct reflect.Value, currentStruct reflect.Value, current reflect.Value, errPrefix string, nsPrefix string, errs ValidationErrors, useStructName bool, partial bool, exclude bool, includeExclude map[string]struct{}, isStructOnly bool) { - - if current.Kind() == reflect.Ptr && !current.IsNil() { - current = current.Elem() - } - - if current.Kind() != reflect.Struct && current.Kind() != reflect.Interface { - panic("value passed for validation is not a struct") - } - - v.tranverseStruct(topStruct, currentStruct, current, errPrefix, nsPrefix, errs, useStructName, partial, exclude, includeExclude, nil, nil) -} - -// tranverseStruct traverses a structs fields and then passes them to be validated by traverseField -func (v *Validate) tranverseStruct(topStruct reflect.Value, currentStruct reflect.Value, current reflect.Value, errPrefix string, nsPrefix string, errs ValidationErrors, useStructName bool, partial bool, exclude bool, includeExclude map[string]struct{}, cs *cStruct, ct *cTag) { - - var ok bool - first := len(nsPrefix) == 0 - typ := current.Type() - - cs, ok = v.structCache.Get(typ) - if !ok { - cs = v.extractStructCache(current, typ.Name()) - } - - if useStructName { - errPrefix += cs.Name + namespaceSeparator - - if len(v.fieldNameTag) != 0 { - nsPrefix += cs.Name + namespaceSeparator - } - } - - // structonly tag present don't tranverseFields - // but must still check and run below struct level validation - // if present - if first || ct == nil || ct.typeof != typeStructOnly { + // ct is nil on top level struct, and structs as fields that have no tag info + // so if nil or if not nil and the structonly tag isn't present + if ct == nil || ct.typeof != typeStructOnly { for _, f := range cs.fields { - if partial { + if v.isPartial { - _, ok = includeExclude[errPrefix+f.Name] + _, ok = v.includeExclude[string(append(ns, f.Name...))] - if (ok && exclude) || (!ok && !exclude) { + if (ok && v.hasExcludes) || (!ok && !v.hasExcludes) { continue } } - v.traverseField(topStruct, currentStruct, current.Field(f.Idx), errPrefix, nsPrefix, errs, partial, exclude, includeExclude, cs, f, f.cTags) + v.traverseField(parent, current.Field(f.Idx), ns, actualNs, f, f.cTags) } } // check if any struct level validations, after all field validations already checked. + // first iteration will have no info about nostructlevel tag, and is checked prior to + // calling the next iteration of validateStruct called from traverseField. if cs.fn != nil { - cs.fn(v, &StructLevel{v: v, TopStruct: topStruct, CurrentStruct: current, errPrefix: errPrefix, nsPrefix: nsPrefix, errs: errs}) + + v.slflParent = parent + v.slCurrent = current + v.slNs = ns + v.slActualNs = actualNs + + cs.fn(v) } } // traverseField validates any field, be it a struct or single field, ensures it's validity and passes it along to be validated via it's tag options -func (v *Validate) traverseField(topStruct reflect.Value, currentStruct reflect.Value, current reflect.Value, errPrefix string, nsPrefix string, errs ValidationErrors, partial bool, exclude bool, includeExclude map[string]struct{}, cs *cStruct, cf *cField, ct *cTag) { +func (v *validate) traverseField(parent reflect.Value, current reflect.Value, ns []byte, actualNs []byte, cf *cField, ct *cTag) { - current, kind, nullable := v.extractTypeInternal(current, false) var typ reflect.Type + var kind reflect.Kind + var nullable bool + + current, kind, nullable = v.extractTypeInternal(current, nullable) switch kind { case reflect.Ptr, reflect.Interface, reflect.Invalid: @@ -589,39 +104,44 @@ func (v *Validate) traverseField(topStruct reflect.Value, currentStruct reflect. if ct.hasTag { - ns := errPrefix + cf.Name - if kind == reflect.Invalid { - errs[ns] = &FieldError{ - FieldNamespace: ns, - NameNamespace: nsPrefix + cf.AltName, - Name: cf.AltName, - Field: cf.Name, - Tag: ct.aliasTag, - ActualTag: ct.tag, - Param: ct.param, - Kind: kind, - } + + v.errs = append(v.errs, + &fieldError{ + tag: ct.aliasTag, + actualTag: ct.tag, + ns: string(append(ns, cf.Name...)), + actualNs: string(append(actualNs, cf.AltName...)), + field: cf.AltName, + actualField: cf.Name, + param: ct.param, + kind: kind, + }, + ) + return } - errs[ns] = &FieldError{ - FieldNamespace: ns, - NameNamespace: nsPrefix + cf.AltName, - Name: cf.AltName, - Field: cf.Name, - Tag: ct.aliasTag, - ActualTag: ct.tag, - Param: ct.param, - Value: current.Interface(), - Kind: kind, - Type: current.Type(), - } + v.errs = append(v.errs, + &fieldError{ + tag: ct.aliasTag, + actualTag: ct.tag, + ns: string(append(ns, cf.Name...)), + actualNs: string(append(actualNs, cf.AltName...)), + field: cf.AltName, + actualField: cf.Name, + value: current.Interface(), + param: ct.param, + kind: kind, + typ: current.Type(), + }, + ) return } case reflect.Struct: + typ = current.Type() if typ != timeType { @@ -634,7 +154,7 @@ func (v *Validate) traverseField(topStruct reflect.Value, currentStruct reflect. return } - v.tranverseStruct(topStruct, current, current, errPrefix+cf.Name+namespaceSeparator, nsPrefix+cf.AltName+namespaceSeparator, errs, false, partial, exclude, includeExclude, cs, ct) + v.validateStruct(current, current, typ, append(append(ns, cf.Name...), '.'), append(append(actualNs, cf.AltName...), '.'), ct) return } } @@ -659,7 +179,12 @@ OUTER: case typeOmitEmpty: - if !nullable && !HasValue(v, topStruct, currentStruct, current, typ, kind, blank) { + // set Field Level fields + v.slflParent = parent + v.flField = current + v.flParam = "" + + if !nullable && !hasValue(v) { return } @@ -676,12 +201,12 @@ OUTER: case reflect.Slice, reflect.Array: for i := 0; i < current.Len(); i++ { - v.traverseField(topStruct, currentStruct, current.Index(i), errPrefix, nsPrefix, errs, partial, exclude, includeExclude, cs, &cField{Name: fmt.Sprintf(arrayIndexFieldName, cf.Name, i), AltName: fmt.Sprintf(arrayIndexFieldName, cf.AltName, i)}, ct) + v.traverseField(parent, current.Index(i), ns, actualNs, &cField{Name: fmt.Sprintf(arrayIndexFieldName, cf.Name, i), AltName: fmt.Sprintf(arrayIndexFieldName, cf.AltName, i)}, ct) } case reflect.Map: for _, key := range current.MapKeys() { - v.traverseField(topStruct, currentStruct, current.MapIndex(key), errPrefix, nsPrefix, errs, partial, exclude, includeExclude, cs, &cField{Name: fmt.Sprintf(mapIndexFieldName, cf.Name, key.Interface()), AltName: fmt.Sprintf(mapIndexFieldName, cf.AltName, key.Interface())}, ct) + v.traverseField(parent, current.MapIndex(key), ns, actualNs, &cField{Name: fmt.Sprintf(mapIndexFieldName, cf.Name, key.Interface()), AltName: fmt.Sprintf(mapIndexFieldName, cf.AltName, key.Interface())}, ct) } default: @@ -694,11 +219,16 @@ OUTER: case typeOr: - errTag := blank + errTag := "" for { - if ct.fn(v, topStruct, currentStruct, current, typ, kind, ct.param) { + // set Field Level fields + v.slflParent = parent + v.flField = current + v.flParam = ct.param + + if ct.fn(v) { // drain rest of the 'or' values, then continue or leave for { @@ -720,32 +250,39 @@ OUTER: if ct.next == nil { // if we get here, no valid 'or' value and no more tags - ns := errPrefix + cf.Name - if ct.hasAlias { - errs[ns] = &FieldError{ - FieldNamespace: ns, - NameNamespace: nsPrefix + cf.AltName, - Name: cf.AltName, - Field: cf.Name, - Tag: ct.aliasTag, - ActualTag: ct.actualAliasTag, - Value: current.Interface(), - Type: typ, - Kind: kind, - } + + v.errs = append(v.errs, + &fieldError{ + tag: ct.aliasTag, + actualTag: ct.actualAliasTag, + ns: string(append(ns, cf.Name...)), + actualNs: string(append(actualNs, cf.AltName...)), + field: cf.AltName, + actualField: cf.Name, + value: current.Interface(), + param: ct.param, + kind: kind, + typ: typ, + }, + ) + } else { - errs[errPrefix+cf.Name] = &FieldError{ - FieldNamespace: ns, - NameNamespace: nsPrefix + cf.AltName, - Name: cf.AltName, - Field: cf.Name, - Tag: errTag[1:], - ActualTag: errTag[1:], - Value: current.Interface(), - Type: typ, - Kind: kind, - } + + v.errs = append(v.errs, + &fieldError{ + tag: errTag[1:], + actualTag: errTag[1:], + ns: string(append(ns, cf.Name...)), + actualNs: string(append(actualNs, cf.AltName...)), + field: cf.AltName, + actualField: cf.Name, + value: current.Interface(), + param: ct.param, + kind: kind, + typ: typ, + }, + ) } return @@ -755,22 +292,28 @@ OUTER: } default: - if !ct.fn(v, topStruct, currentStruct, current, typ, kind, ct.param) { - - ns := errPrefix + cf.Name - - errs[ns] = &FieldError{ - FieldNamespace: ns, - NameNamespace: nsPrefix + cf.AltName, - Name: cf.AltName, - Field: cf.Name, - Tag: ct.aliasTag, - ActualTag: ct.tag, - Value: current.Interface(), - Param: ct.param, - Type: typ, - Kind: kind, - } + + // set Field Level fields + v.slflParent = parent + v.flField = current + v.flParam = ct.param + + if !ct.fn(v) { + + v.errs = append(v.errs, + &fieldError{ + tag: ct.aliasTag, + actualTag: ct.tag, + ns: string(append(ns, cf.Name...)), + actualNs: string(append(actualNs, cf.AltName...)), + field: cf.AltName, + actualField: cf.Name, + value: current.Interface(), + param: ct.param, + kind: kind, + typ: typ, + }, + ) return @@ -779,4 +322,5 @@ OUTER: ct = ct.next } } + } diff --git a/validator_instance.go b/validator_instance.go new file mode 100644 index 0000000..8ade9cc --- /dev/null +++ b/validator_instance.go @@ -0,0 +1,442 @@ +package validator + +import ( + "errors" + "fmt" + "reflect" + "strings" + "sync" + "time" +) + +const ( + defaultTagName = "validate" + utf8HexComma = "0x2C" + utf8Pipe = "0x7C" + tagSeparator = "," + orSeparator = "|" + tagKeySeparator = "=" + structOnlyTag = "structonly" + noStructLevelTag = "nostructlevel" + omitempty = "omitempty" + skipValidationTag = "-" + diveTag = "dive" + namespaceSeparator = "." + leftBracket = "[" + rightBracket = "]" + restrictedTagChars = ".[],|=+()`~!@#$%^&*\\\"/?<>{}" + restrictedAliasErr = "Alias '%s' either contains restricted characters or is the same as a restricted tag needed for normal operation" + restrictedTagErr = "Tag '%s' either contains restricted characters or is the same as a restricted tag needed for normal operation" +) + +var ( + timeType = reflect.TypeOf(time.Time{}) + defaultCField = new(cField) +) + +// CustomTypeFunc allows for overriding or adding custom field type handler functions +// field = field value of the type to return a value to be validated +// example Valuer from sql drive see https://golang.org/src/database/sql/driver/types.go?s=1210:1293#L29 +type CustomTypeFunc func(field reflect.Value) interface{} + +// TagNameFunc allows for adding of a custom tag name parser +type TagNameFunc func(field reflect.StructField) string + +// Validate contains the validator settings and cache +type Validate struct { + tagName string + pool *sync.Pool + hasCustomFuncs bool + hasTagNameFunc bool + tagNameFunc TagNameFunc + structLevelFuncs map[reflect.Type]StructLevelFunc + customFuncs map[reflect.Type]CustomTypeFunc + aliases map[string]string + validations map[string]Func + tagCache *tagCache + structCache *structCache +} + +// New returns a new instacne of 'validate' with sane defaults. +func New() *Validate { + + tc := new(tagCache) + tc.m.Store(make(map[string]*cTag)) + + sc := new(structCache) + sc.m.Store(make(map[reflect.Type]*cStruct)) + + v := &Validate{ + tagName: defaultTagName, + aliases: make(map[string]string, len(bakedInAliases)), + validations: make(map[string]Func, len(bakedInValidators)), + tagCache: tc, + structCache: sc, + } + + // must copy alias validators for separate validations to be used in each validator instance + for k, val := range bakedInAliases { + v.RegisterAlias(k, val) + } + + // must copy validators for separate validations to be used in each instance + for k, val := range bakedInValidators { + + // no need to error check here, baked in will alwaays be valid + v.RegisterValidation(k, val) + } + + v.pool = &sync.Pool{ + New: func() interface{} { + return &validate{ + v: v, + } + }, + } + + return v +} + +// SetTagName allows for changing of the default tag name of 'validate' +func (v *Validate) SetTagName(name string) { + v.tagName = name +} + +// RegisterTagNameFunc registers a function to get another name from the +// StructField eg. the JSON name +func (v *Validate) RegisterTagNameFunc(fn TagNameFunc) { + v.tagNameFunc = fn + v.hasTagNameFunc = true +} + +// RegisterValidation adds a validation with the given tag +// +// NOTES: +// - if the key already exists, the previous validation function will be replaced. +// - this method is not thread-safe it is intended that these all be registered prior to any validation +func (v *Validate) RegisterValidation(tag string, fn Func) error { + + if len(tag) == 0 { + return errors.New("Function Key cannot be empty") + } + + if fn == nil { + return errors.New("Function cannot be empty") + } + + _, ok := restrictedTags[tag] + + if ok || strings.ContainsAny(tag, restrictedTagChars) { + panic(fmt.Sprintf(restrictedTagErr, tag)) + } + + v.validations[tag] = fn + + return nil +} + +// RegisterAlias registers a mapping of a single validation tag that +// defines a common or complex set of validation(s) to simplify adding validation +// to structs. +// +// NOTE: this function is not thread-safe it is intended that these all be registered prior to any validation +func (v *Validate) RegisterAlias(alias, tags string) { + + _, ok := restrictedTags[alias] + + if ok || strings.ContainsAny(alias, restrictedTagChars) { + panic(fmt.Sprintf(restrictedAliasErr, alias)) + } + + v.aliases[alias] = tags +} + +// RegisterStructValidation registers a StructLevelFunc against a number of types. +// This is akin to implementing the 'Validatable' interface, but for structs for which +// you may not have access or rights to change. +// +// NOTES: +// - if this and the 'Validatable' interface are implemented the Struct Level takes precedence as to enable +// a struct out of your control's validation to be overridden +// - this method is not thread-safe it is intended that these all be registered prior to any validation +func (v *Validate) RegisterStructValidation(fn StructLevelFunc, types ...interface{}) { + + if v.structLevelFuncs == nil { + v.structLevelFuncs = make(map[reflect.Type]StructLevelFunc) + } + + for _, t := range types { + v.structLevelFuncs[reflect.TypeOf(t)] = fn + } +} + +// RegisterCustomTypeFunc registers a CustomTypeFunc against a number of types +// +// NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation +func (v *Validate) RegisterCustomTypeFunc(fn CustomTypeFunc, types ...interface{}) { + + if v.customFuncs == nil { + v.customFuncs = make(map[reflect.Type]CustomTypeFunc) + } + + for _, t := range types { + v.customFuncs[reflect.TypeOf(t)] = fn + } +} + +// Struct validates a structs exposed fields, and automatically validates nested structs, unless otherwise specified. +// +// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. +// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. +func (v *Validate) Struct(s interface{}) (err error) { + + val := reflect.ValueOf(s) + top := val + + if val.Kind() == reflect.Ptr && !val.IsNil() { + val = val.Elem() + } + + typ := val.Type() + + if val.Kind() != reflect.Struct || typ == timeType { + return &InvalidValidationError{Type: typ} + } + + // good to validate + vd := v.pool.Get().(*validate) + vd.top = top + vd.isPartial = false + // vd.hasExcludes = false // only need to reset in StructPartial and StructExcept + + vd.validateStruct(top, val, typ, vd.ns[0:0], vd.actualNs[0:0], nil) + + if len(vd.errs) > 0 { + err = vd.errs + vd.errs = nil + } + + v.pool.Put(vd) + + return +} + +// StructPartial validates the fields passed in only, ignoring all others. +// Fields may be provided in a namespaced fashion relative to the struct provided +// eg. NestedStruct.Field or NestedArrayField[0].Struct.Name +// +// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. +// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. +func (v *Validate) StructPartial(s interface{}, fields ...string) (err error) { + + val := reflect.ValueOf(s) + top := val + + if val.Kind() == reflect.Ptr && !val.IsNil() { + val = val.Elem() + } + + typ := val.Type() + + if val.Kind() != reflect.Struct || typ == timeType { + return &InvalidValidationError{Type: typ} + } + + // good to validate + vd := v.pool.Get().(*validate) + vd.top = top + vd.isPartial = true + vd.hasExcludes = false + vd.includeExclude = make(map[string]struct{}) + + name := typ.Name() + + if fields != nil { + for _, k := range fields { + + flds := strings.Split(k, namespaceSeparator) + if len(flds) > 0 { + + key := name + namespaceSeparator + for _, s := range flds { + + idx := strings.Index(s, leftBracket) + + if idx != -1 { + for idx != -1 { + key += s[:idx] + vd.includeExclude[key] = struct{}{} + + idx2 := strings.Index(s, rightBracket) + idx2++ + key += s[idx:idx2] + vd.includeExclude[key] = struct{}{} + s = s[idx2:] + idx = strings.Index(s, leftBracket) + } + } else { + + key += s + vd.includeExclude[key] = struct{}{} + } + + key += namespaceSeparator + } + } + } + } + + vd.validateStruct(top, val, typ, vd.ns[0:0], vd.actualNs[0:0], nil) + + if len(vd.errs) > 0 { + err = vd.errs + vd.errs = nil + } + + v.pool.Put(vd) + + return +} + +// StructExcept validates all fields except the ones passed in. +// Fields may be provided in a namespaced fashion relative to the struct provided +// i.e. NestedStruct.Field or NestedArrayField[0].Struct.Name +// +// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. +// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. +func (v *Validate) StructExcept(s interface{}, fields ...string) (err error) { + + val := reflect.ValueOf(s) + top := val + + if val.Kind() == reflect.Ptr && !val.IsNil() { + val = val.Elem() + } + + typ := val.Type() + + if val.Kind() != reflect.Struct || typ == timeType { + return &InvalidValidationError{Type: typ} + } + + // good to validate + vd := v.pool.Get().(*validate) + vd.top = top + vd.isPartial = true + vd.hasExcludes = true + vd.includeExclude = make(map[string]struct{}) + + name := typ.Name() + + for _, key := range fields { + vd.includeExclude[name+namespaceSeparator+key] = struct{}{} + } + + vd.validateStruct(top, val, typ, vd.ns[0:0], vd.actualNs[0:0], nil) + + if len(vd.errs) > 0 { + err = vd.errs + vd.errs = nil + } + + v.pool.Put(vd) + + return +} + +// func (v *validate) traverseField(parent reflect.Value, current reflect.Value, ns []byte, actualNs []byte, cf *cField, ct *cTag) { + +// Var validates a single variable using tag style validation. +// eg. +// var i int +// validate.Var(i, "gt=1,lt=10") +// +// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. +// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. +// validate Array, Slice and maps fields which may contain more than one error +func (v *Validate) Var(field interface{}, tag string) (err error) { + + if len(tag) == 0 || tag == skipValidationTag { + return nil + } + + // find cached tag + ctag, ok := v.tagCache.Get(tag) + if !ok { + v.tagCache.lock.Lock() + defer v.tagCache.lock.Unlock() + + // could have been multiple trying to access, but once first is done this ensures tag + // isn't parsed again. + ctag, ok = v.tagCache.Get(tag) + if !ok { + ctag, _ = v.parseFieldTagsRecursive(tag, "", "", false) + v.tagCache.Set(tag, ctag) + } + } + + val := reflect.ValueOf(field) + + vd := v.pool.Get().(*validate) + vd.top = val + vd.isPartial = false + + vd.traverseField(val, val, vd.ns[0:0], vd.actualNs[0:0], defaultCField, ctag) + + if len(vd.errs) > 0 { + err = vd.errs + vd.errs = nil + } + + v.pool.Put(vd) + + return +} + +// VarWithValue validates a single variable, against another variable/field's value using tag style validation +// eg. +// s1 := "abcd" +// s2 := "abcd" +// validate.VarWithValue(s1, s2, "eqcsfield") // returns true +// +// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. +// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. +// validate Array, Slice and maps fields which may contain more than one error +func (v *Validate) VarWithValue(field interface{}, other interface{}, tag string) (err error) { + + if len(tag) == 0 || tag == skipValidationTag { + return nil + } + + // find cached tag + ctag, ok := v.tagCache.Get(tag) + if !ok { + v.tagCache.lock.Lock() + defer v.tagCache.lock.Unlock() + + // could have been multiple trying to access, but once first is done this ensures tag + // isn't parsed again. + ctag, ok = v.tagCache.Get(tag) + if !ok { + ctag, _ = v.parseFieldTagsRecursive(tag, "", "", false) + v.tagCache.Set(tag, ctag) + } + } + + otherVal := reflect.ValueOf(other) + + vd := v.pool.Get().(*validate) + vd.top = otherVal + vd.isPartial = false + + vd.traverseField(otherVal, reflect.ValueOf(field), vd.ns[0:0], vd.actualNs[0:0], defaultCField, ctag) + + if len(vd.errs) > 0 { + err = vd.errs + vd.errs = nil + } + + v.pool.Put(vd) + + return +} diff --git a/validator_test.go b/validator_test.go index ee61527..30b2fab 100644 --- a/validator_test.go +++ b/validator_test.go @@ -1,13 +1,9 @@ package validator import ( - "database/sql" "database/sql/driver" - "encoding/json" - "fmt" "reflect" "testing" - "time" . "gopkg.in/go-playground/assert.v1" ) @@ -70,115 +66,112 @@ type TestString struct { Iface I } -type TestInt32 struct { - Required int `validate:"required"` - Len int `validate:"len=10"` - Min int `validate:"min=1"` - Max int `validate:"max=10"` - MinMax int `validate:"min=1,max=10"` - Lt int `validate:"lt=10"` - Lte int `validate:"lte=10"` - Gt int `validate:"gt=10"` - Gte int `validate:"gte=10"` - OmitEmpty int `validate:"omitempty,min=1,max=10"` -} - -type TestUint64 struct { - Required uint64 `validate:"required"` - Len uint64 `validate:"len=10"` - Min uint64 `validate:"min=1"` - Max uint64 `validate:"max=10"` - MinMax uint64 `validate:"min=1,max=10"` - OmitEmpty uint64 `validate:"omitempty,min=1,max=10"` -} - -type TestFloat64 struct { - Required float64 `validate:"required"` - Len float64 `validate:"len=10"` - Min float64 `validate:"min=1"` - Max float64 `validate:"max=10"` - MinMax float64 `validate:"min=1,max=10"` - Lte float64 `validate:"lte=10"` - OmitEmpty float64 `validate:"omitempty,min=1,max=10"` -} - -type TestSlice struct { - Required []int `validate:"required"` - Len []int `validate:"len=10"` - Min []int `validate:"min=1"` - Max []int `validate:"max=10"` - MinMax []int `validate:"min=1,max=10"` - OmitEmpty []int `validate:"omitempty,min=1,max=10"` -} - -var validate = New(&Config{TagName: "validate"}) +// type TestUint64 struct { +// Required uint64 `validate:"required"` +// Len uint64 `validate:"len=10"` +// Min uint64 `validate:"min=1"` +// Max uint64 `validate:"max=10"` +// MinMax uint64 `validate:"min=1,max=10"` +// OmitEmpty uint64 `validate:"omitempty,min=1,max=10"` +// } + +// type TestFloat64 struct { +// Required float64 `validate:"required"` +// Len float64 `validate:"len=10"` +// Min float64 `validate:"min=1"` +// Max float64 `validate:"max=10"` +// MinMax float64 `validate:"min=1,max=10"` +// Lte float64 `validate:"lte=10"` +// OmitEmpty float64 `validate:"omitempty,min=1,max=10"` +// } + +// type TestSlice struct { +// Required []int `validate:"required"` +// Len []int `validate:"len=10"` +// Min []int `validate:"min=1"` +// Max []int `validate:"max=10"` +// MinMax []int `validate:"min=1,max=10"` +// OmitEmpty []int `validate:"omitempty,min=1,max=10"` +// } + +// var validate = New(&Config{TagName: "validate"}) func AssertError(t *testing.T, err error, key, field, expectedTag string) { errs := err.(ValidationErrors) - val, ok := errs[key] - EqualSkip(t, 2, ok, true) - NotEqualSkip(t, 2, val, nil) - EqualSkip(t, 2, val.Field, field) - EqualSkip(t, 2, val.Tag, expectedTag) + found := false + var fe FieldError + + for i := 0; i < len(errs); i++ { + if errs[i].Namespace() == key { + found = true + fe = errs[i] + break + } + } + + EqualSkip(t, 2, found, true) + NotEqualSkip(t, 2, fe, nil) + EqualSkip(t, 2, fe.Field(), field) + EqualSkip(t, 2, fe.Tag(), expectedTag) } type valuer struct { Name string } -func (v valuer) Value() (driver.Value, error) { +// func (v valuer) Value() (driver.Value, error) { - if v.Name == "errorme" { - panic("SQL Driver Valuer error: some kind of error") - // return nil, errors.New("some kind of error") - } +// if v.Name == "errorme" { +// panic("SQL Driver Valuer error: some kind of error") +// // return nil, errors.New("some kind of error") +// } - if len(v.Name) == 0 { - return nil, nil - } +// if len(v.Name) == 0 { +// return nil, nil +// } - return v.Name, nil -} +// return v.Name, nil +// } -type MadeUpCustomType struct { - FirstName string - LastName string -} +// type MadeUpCustomType struct { +// FirstName string +// LastName string +// } -func ValidateCustomType(field reflect.Value) interface{} { - if cust, ok := field.Interface().(MadeUpCustomType); ok { +// func ValidateCustomType(field reflect.Value) interface{} { +// if cust, ok := field.Interface().(MadeUpCustomType); ok { - if len(cust.FirstName) == 0 || len(cust.LastName) == 0 { - return "" - } +// if len(cust.FirstName) == 0 || len(cust.LastName) == 0 { +// return "" +// } - return cust.FirstName + " " + cust.LastName - } +// return cust.FirstName + " " + cust.LastName +// } - return "" -} +// return "" +// } -func OverrideIntTypeForSomeReason(field reflect.Value) interface{} { +// func OverrideIntTypeForSomeReason(field reflect.Value) interface{} { - if i, ok := field.Interface().(int); ok { - if i == 1 { - return "1" - } +// if i, ok := field.Interface().(int); ok { +// if i == 1 { +// return "1" +// } - if i == 2 { - return "12" - } - } +// if i == 2 { +// return "12" +// } +// } - return "" -} +// return "" +// } -type CustomMadeUpStruct struct { - MadeUp MadeUpCustomType `validate:"required"` - OverriddenInt int `validate:"gt=1"` -} +// type CustomMadeUpStruct struct { +// MadeUp MadeUpCustomType `validate:"required"` +// OverriddenInt int `validate:"gt=1"` +// } func ValidateValuerType(field reflect.Value) interface{} { @@ -196,5434 +189,5447 @@ func ValidateValuerType(field reflect.Value) interface{} { return nil } -type TestPartial struct { - NoTag string - BlankTag string `validate:""` - Required string `validate:"required"` - SubSlice []*SubTest `validate:"required,dive"` - Sub *SubTest - SubIgnore *SubTest `validate:"-"` - Anonymous struct { - A string `validate:"required"` - ASubSlice []*SubTest `validate:"required,dive"` - - SubAnonStruct []struct { - Test string `validate:"required"` - OtherTest string `validate:"required"` - } `validate:"required,dive"` - } -} +// type TestPartial struct { +// NoTag string +// BlankTag string `validate:""` +// Required string `validate:"required"` +// SubSlice []*SubTest `validate:"required,dive"` +// Sub *SubTest +// SubIgnore *SubTest `validate:"-"` +// Anonymous struct { +// A string `validate:"required"` +// ASubSlice []*SubTest `validate:"required,dive"` + +// SubAnonStruct []struct { +// Test string `validate:"required"` +// OtherTest string `validate:"required"` +// } `validate:"required,dive"` +// } +// } type TestStruct struct { String string `validate:"required" json:"StringVal"` } -func StructValidationTestStructSuccess(v *Validate, structLevel *StructLevel) { +func StructValidationTestStructSuccess(sl StructLevel) { - st := structLevel.CurrentStruct.Interface().(TestStruct) + st := sl.Current().Interface().(TestStruct) if st.String != "good value" { - structLevel.ReportError(reflect.ValueOf(st.String), "String", "StringVal", "badvalueteststruct") + sl.ReportError(reflect.ValueOf(st.String), "String", "StringVal", "badvalueteststruct") } } -func StructValidationTestStruct(v *Validate, structLevel *StructLevel) { +func StructValidationTestStruct(sl StructLevel) { - st := structLevel.CurrentStruct.Interface().(TestStruct) + st := sl.Current().Interface().(TestStruct) if st.String != "bad value" { - structLevel.ReportError(reflect.ValueOf(st.String), "String", "StringVal", "badvalueteststruct") + sl.ReportError(reflect.ValueOf(st.String), "String", "StringVal", "badvalueteststruct") } } -func StructValidationBadTestStructFieldName(v *Validate, structLevel *StructLevel) { +// func StructValidationBadTestStructFieldName(v *Validate, structLevel *StructLevel) { - st := structLevel.CurrentStruct.Interface().(TestStruct) +// st := structLevel.CurrentStruct.Interface().(TestStruct) - if st.String != "bad value" { - structLevel.ReportError(reflect.ValueOf(st.String), "", "StringVal", "badvalueteststruct") - } -} +// if st.String != "bad value" { +// structLevel.ReportError(reflect.ValueOf(st.String), "", "StringVal", "badvalueteststruct") +// } +// } -func StructValidationBadTestStructTag(v *Validate, structLevel *StructLevel) { +// func StructValidationBadTestStructTag(v *Validate, structLevel *StructLevel) { - st := structLevel.CurrentStruct.Interface().(TestStruct) +// st := structLevel.CurrentStruct.Interface().(TestStruct) - if st.String != "bad value" { - structLevel.ReportError(reflect.ValueOf(st.String), "String", "StringVal", "") - } -} +// if st.String != "bad value" { +// structLevel.ReportError(reflect.ValueOf(st.String), "String", "StringVal", "") +// } +// } -func StructValidationNoTestStructCustomName(v *Validate, structLevel *StructLevel) { +// func StructValidationNoTestStructCustomName(v *Validate, structLevel *StructLevel) { - st := structLevel.CurrentStruct.Interface().(TestStruct) +// st := structLevel.CurrentStruct.Interface().(TestStruct) - if st.String != "bad value" { - structLevel.ReportError(reflect.ValueOf(st.String), "String", "", "badvalueteststruct") - } -} +// if st.String != "bad value" { +// structLevel.ReportError(reflect.ValueOf(st.String), "String", "", "badvalueteststruct") +// } +// } -func StructValidationTestStructInvalid(v *Validate, structLevel *StructLevel) { +// func StructValidationTestStructInvalid(v *Validate, structLevel *StructLevel) { - st := structLevel.CurrentStruct.Interface().(TestStruct) +// st := structLevel.CurrentStruct.Interface().(TestStruct) - if st.String != "bad value" { - structLevel.ReportError(reflect.ValueOf(nil), "String", "StringVal", "badvalueteststruct") - } -} +// if st.String != "bad value" { +// structLevel.ReportError(reflect.ValueOf(nil), "String", "StringVal", "badvalueteststruct") +// } +// } -func StructValidationTestStructReturnValidationErrors(v *Validate, structLevel *StructLevel) { +// func StructValidationTestStructReturnValidationErrors(v *Validate, structLevel *StructLevel) { - s := structLevel.CurrentStruct.Interface().(TestStructReturnValidationErrors) +// s := structLevel.CurrentStruct.Interface().(TestStructReturnValidationErrors) - errs := v.Struct(s.Inner1.Inner2) - if errs == nil { - return - } +// errs := v.Struct(s.Inner1.Inner2) +// if errs == nil { +// return +// } - structLevel.ReportValidationErrors("Inner1.", errs.(ValidationErrors)) -} +// structLevel.ReportValidationErrors("Inner1.", errs.(ValidationErrors)) +// } -func StructValidationTestStructReturnValidationErrors2(v *Validate, structLevel *StructLevel) { +// func StructValidationTestStructReturnValidationErrors2(v *Validate, structLevel *StructLevel) { - s := structLevel.CurrentStruct.Interface().(TestStructReturnValidationErrors) +// s := structLevel.CurrentStruct.Interface().(TestStructReturnValidationErrors) - errs := v.Struct(s.Inner1.Inner2) - if errs == nil { - return - } +// errs := v.Struct(s.Inner1.Inner2) +// if errs == nil { +// return +// } - structLevel.ReportValidationErrors("Inner1.|Inner1JSON.", errs.(ValidationErrors)) -} +// structLevel.ReportValidationErrors("Inner1.|Inner1JSON.", errs.(ValidationErrors)) +// } -type TestStructReturnValidationErrorsInner2 struct { - String string `validate:"required" json:"JSONString"` -} +// type TestStructReturnValidationErrorsInner2 struct { +// String string `validate:"required" json:"JSONString"` +// } -type TestStructReturnValidationErrorsInner1 struct { - Inner2 *TestStructReturnValidationErrorsInner2 -} +// type TestStructReturnValidationErrorsInner1 struct { +// Inner2 *TestStructReturnValidationErrorsInner2 +// } -type TestStructReturnValidationErrors struct { - Inner1 *TestStructReturnValidationErrorsInner1 `json:"Inner1JSON"` -} +// type TestStructReturnValidationErrors struct { +// Inner1 *TestStructReturnValidationErrorsInner1 `json:"Inner1JSON"` +// } -type Inner2Namespace struct { - String []string `validate:"dive,required" json:"JSONString"` -} +// type Inner2Namespace struct { +// String []string `validate:"dive,required" json:"JSONString"` +// } -type Inner1Namespace struct { - Inner2 *Inner2Namespace `json:"Inner2JSON"` -} +// type Inner1Namespace struct { +// Inner2 *Inner2Namespace `json:"Inner2JSON"` +// } -type Namespace struct { - Inner1 *Inner1Namespace `json:"Inner1JSON"` -} +// type Namespace struct { +// Inner1 *Inner1Namespace `json:"Inner1JSON"` +// } -func TestNameNamespace(t *testing.T) { +// func TestNameNamespace(t *testing.T) { - config := &Config{ - TagName: "validate", - FieldNameTag: "json", - } +// config := &Config{ +// TagName: "validate", +// FieldNameTag: "json", +// } - v1 := New(config) - i2 := &Inner2Namespace{String: []string{"ok", "ok", "ok"}} - i1 := &Inner1Namespace{Inner2: i2} - ns := &Namespace{Inner1: i1} +// v1 := New(config) +// i2 := &Inner2Namespace{String: []string{"ok", "ok", "ok"}} +// i1 := &Inner1Namespace{Inner2: i2} +// ns := &Namespace{Inner1: i1} - errs := v1.Struct(ns) - Equal(t, errs, nil) +// errs := v1.Struct(ns) +// Equal(t, errs, nil) - i2.String[1] = "" +// i2.String[1] = "" - errs = v1.Struct(ns) - NotEqual(t, errs, nil) +// errs = v1.Struct(ns) +// NotEqual(t, errs, nil) - ve := errs.(ValidationErrors) - Equal(t, len(ve), 1) - AssertError(t, errs, "Namespace.Inner1.Inner2.String[1]", "String[1]", "required") +// ve := errs.(ValidationErrors) +// Equal(t, len(ve), 1) +// AssertError(t, errs, "Namespace.Inner1.Inner2.String[1]", "String[1]", "required") - fe, ok := ve["Namespace.Inner1.Inner2.String[1]"] - Equal(t, ok, true) +// fe, ok := ve["Namespace.Inner1.Inner2.String[1]"] +// Equal(t, ok, true) - Equal(t, fe.Field, "String[1]") - Equal(t, fe.FieldNamespace, "Namespace.Inner1.Inner2.String[1]") - Equal(t, fe.Name, "JSONString[1]") - Equal(t, fe.NameNamespace, "Namespace.Inner1JSON.Inner2JSON.JSONString[1]") -} +// Equal(t, fe.Field, "String[1]") +// Equal(t, fe.FieldNamespace, "Namespace.Inner1.Inner2.String[1]") +// Equal(t, fe.Name, "JSONString[1]") +// Equal(t, fe.NameNamespace, "Namespace.Inner1JSON.Inner2JSON.JSONString[1]") +// } -func TestAnonymous(t *testing.T) { +// func TestAnonymous(t *testing.T) { - v2 := New(&Config{TagName: "validate", FieldNameTag: "json"}) +// v2 := New(&Config{TagName: "validate", FieldNameTag: "json"}) + +// type Test struct { +// Anonymous struct { +// A string `validate:"required" json:"EH"` +// } +// AnonymousB struct { +// B string `validate:"required" json:"BEE"` +// } +// anonymousC struct { +// c string `validate:"required"` +// } +// } + +// tst := &Test{ +// Anonymous: struct { +// A string `validate:"required" json:"EH"` +// }{ +// A: "1", +// }, +// AnonymousB: struct { +// B string `validate:"required" json:"BEE"` +// }{ +// B: "", +// }, +// anonymousC: struct { +// c string `validate:"required"` +// }{ +// c: "", +// }, +// } + +// err := v2.Struct(tst) +// NotEqual(t, err, nil) + +// errs := err.(ValidationErrors) + +// Equal(t, len(errs), 1) +// AssertError(t, errs, "Test.AnonymousB.B", "B", "required") +// Equal(t, errs["Test.AnonymousB.B"].Field, "B") +// Equal(t, errs["Test.AnonymousB.B"].Name, "BEE") + +// s := struct { +// c string `validate:"required"` +// }{ +// c: "", +// } + +// err = v2.Struct(s) +// Equal(t, err, nil) +// } + +// func TestAnonymousSameStructDifferentTags(t *testing.T) { + +// v2 := New(&Config{TagName: "validate", FieldNameTag: "json"}) + +// type Test struct { +// A interface{} +// } + +// tst := &Test{ +// A: struct { +// A string `validate:"required"` +// }{ +// A: "", +// }, +// } + +// err := v2.Struct(tst) +// NotEqual(t, err, nil) + +// errs := err.(ValidationErrors) + +// Equal(t, len(errs), 1) +// AssertError(t, errs, "Test.A.A", "A", "required") + +// tst = &Test{ +// A: struct { +// A string `validate:"omitempty,required"` +// }{ +// A: "", +// }, +// } + +// err = v2.Struct(tst) +// Equal(t, err, nil) +// } + +// func TestStructLevelReturnValidationErrors(t *testing.T) { +// config := &Config{ +// TagName: "validate", +// } + +// v1 := New(config) +// v1.RegisterStructValidation(StructValidationTestStructReturnValidationErrors, TestStructReturnValidationErrors{}) + +// inner2 := &TestStructReturnValidationErrorsInner2{ +// String: "I'm HERE", +// } + +// inner1 := &TestStructReturnValidationErrorsInner1{ +// Inner2: inner2, +// } + +// val := &TestStructReturnValidationErrors{ +// Inner1: inner1, +// } + +// errs := v1.Struct(val) +// Equal(t, errs, nil) + +// inner2.String = "" + +// errs = v1.Struct(val) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.(ValidationErrors)), 2) +// AssertError(t, errs, "TestStructReturnValidationErrors.Inner1.Inner2.String", "String", "required") +// // this is an extra error reported from struct validation +// AssertError(t, errs, "TestStructReturnValidationErrors.Inner1.String", "String", "required") +// } - type Test struct { - Anonymous struct { - A string `validate:"required" json:"EH"` - } - AnonymousB struct { - B string `validate:"required" json:"BEE"` - } - anonymousC struct { - c string `validate:"required"` - } - } +// func TestStructLevelReturnValidationErrorsWithJSON(t *testing.T) { +// config := &Config{ +// TagName: "validate", +// FieldNameTag: "json", +// } - tst := &Test{ - Anonymous: struct { - A string `validate:"required" json:"EH"` - }{ - A: "1", - }, - AnonymousB: struct { - B string `validate:"required" json:"BEE"` - }{ - B: "", - }, - anonymousC: struct { - c string `validate:"required"` - }{ - c: "", - }, - } +// v1 := New(config) +// v1.RegisterStructValidation(StructValidationTestStructReturnValidationErrors2, TestStructReturnValidationErrors{}) - err := v2.Struct(tst) - NotEqual(t, err, nil) +// inner2 := &TestStructReturnValidationErrorsInner2{ +// String: "I'm HERE", +// } - errs := err.(ValidationErrors) +// inner1 := &TestStructReturnValidationErrorsInner1{ +// Inner2: inner2, +// } - Equal(t, len(errs), 1) - AssertError(t, errs, "Test.AnonymousB.B", "B", "required") - Equal(t, errs["Test.AnonymousB.B"].Field, "B") - Equal(t, errs["Test.AnonymousB.B"].Name, "BEE") +// val := &TestStructReturnValidationErrors{ +// Inner1: inner1, +// } - s := struct { - c string `validate:"required"` - }{ - c: "", - } +// errs := v1.Struct(val) +// Equal(t, errs, nil) - err = v2.Struct(s) - Equal(t, err, nil) -} +// inner2.String = "" -func TestAnonymousSameStructDifferentTags(t *testing.T) { +// errs = v1.Struct(val) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.(ValidationErrors)), 2) +// AssertError(t, errs, "TestStructReturnValidationErrors.Inner1.Inner2.String", "String", "required") +// // this is an extra error reported from struct validation, it's a badly formatted one, but on purpose +// AssertError(t, errs, "TestStructReturnValidationErrors.Inner1.String", "String", "required") - v2 := New(&Config{TagName: "validate", FieldNameTag: "json"}) +// fe, ok := errs.(ValidationErrors)["TestStructReturnValidationErrors.Inner1.Inner2.String"] +// Equal(t, ok, true) - type Test struct { - A interface{} - } +// // check for proper JSON namespace +// Equal(t, fe.Field, "String") +// Equal(t, fe.Name, "JSONString") +// Equal(t, fe.FieldNamespace, "TestStructReturnValidationErrors.Inner1.Inner2.String") +// Equal(t, fe.NameNamespace, "TestStructReturnValidationErrors.Inner1JSON.Inner2.JSONString") - tst := &Test{ - A: struct { - A string `validate:"required"` - }{ - A: "", - }, - } +// fe, ok = errs.(ValidationErrors)["TestStructReturnValidationErrors.Inner1.String"] +// Equal(t, ok, true) - err := v2.Struct(tst) - NotEqual(t, err, nil) +// // check for proper JSON namespace +// Equal(t, fe.Field, "String") +// Equal(t, fe.Name, "JSONString") +// Equal(t, fe.FieldNamespace, "TestStructReturnValidationErrors.Inner1.String") +// Equal(t, fe.NameNamespace, "TestStructReturnValidationErrors.Inner1JSON.JSONString") +// } - errs := err.(ValidationErrors) +// func TestStructLevelValidations(t *testing.T) { - Equal(t, len(errs), 1) - AssertError(t, errs, "Test.A.A", "A", "required") +// config := &Config{ +// TagName: "validate", +// } - tst = &Test{ - A: struct { - A string `validate:"omitempty,required"` - }{ - A: "", - }, - } +// v1 := New(config) +// v1.RegisterStructValidation(StructValidationTestStruct, TestStruct{}) - err = v2.Struct(tst) - Equal(t, err, nil) -} +// tst := &TestStruct{ +// String: "good value", +// } -func TestStructLevelReturnValidationErrors(t *testing.T) { - config := &Config{ - TagName: "validate", - } +// errs := v1.Struct(tst) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "TestStruct.String", "String", "badvalueteststruct") - v1 := New(config) - v1.RegisterStructValidation(StructValidationTestStructReturnValidationErrors, TestStructReturnValidationErrors{}) +// v2 := New(config) +// v2.RegisterStructValidation(StructValidationBadTestStructFieldName, TestStruct{}) - inner2 := &TestStructReturnValidationErrorsInner2{ - String: "I'm HERE", - } +// PanicMatches(t, func() { v2.Struct(tst) }, fieldNameRequired) - inner1 := &TestStructReturnValidationErrorsInner1{ - Inner2: inner2, - } +// v3 := New(config) +// v3.RegisterStructValidation(StructValidationBadTestStructTag, TestStruct{}) - val := &TestStructReturnValidationErrors{ - Inner1: inner1, - } +// PanicMatches(t, func() { v3.Struct(tst) }, tagRequired) - errs := v1.Struct(val) - Equal(t, errs, nil) +// v4 := New(config) +// v4.RegisterStructValidation(StructValidationNoTestStructCustomName, TestStruct{}) - inner2.String = "" +// errs = v4.Struct(tst) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "TestStruct.String", "String", "badvalueteststruct") - errs = v1.Struct(val) - NotEqual(t, errs, nil) - Equal(t, len(errs.(ValidationErrors)), 2) - AssertError(t, errs, "TestStructReturnValidationErrors.Inner1.Inner2.String", "String", "required") - // this is an extra error reported from struct validation - AssertError(t, errs, "TestStructReturnValidationErrors.Inner1.String", "String", "required") -} +// v5 := New(config) +// v5.RegisterStructValidation(StructValidationTestStructInvalid, TestStruct{}) -func TestStructLevelReturnValidationErrorsWithJSON(t *testing.T) { - config := &Config{ - TagName: "validate", - FieldNameTag: "json", - } +// errs = v5.Struct(tst) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "TestStruct.String", "String", "badvalueteststruct") - v1 := New(config) - v1.RegisterStructValidation(StructValidationTestStructReturnValidationErrors2, TestStructReturnValidationErrors{}) +// v6 := New(config) +// v6.RegisterStructValidation(StructValidationTestStructSuccess, TestStruct{}) - inner2 := &TestStructReturnValidationErrorsInner2{ - String: "I'm HERE", - } +// errs = v6.Struct(tst) +// Equal(t, errs, nil) +// } - inner1 := &TestStructReturnValidationErrorsInner1{ - Inner2: inner2, - } +// func TestAliasTags(t *testing.T) { - val := &TestStructReturnValidationErrors{ - Inner1: inner1, - } +// validate.RegisterAliasValidation("iscolor", "hexcolor|rgb|rgba|hsl|hsla") - errs := v1.Struct(val) - Equal(t, errs, nil) +// s := "rgb(255,255,255)" +// errs := validate.Field(s, "iscolor") +// Equal(t, errs, nil) - inner2.String = "" +// s = "" +// errs = validate.Field(s, "omitempty,iscolor") +// Equal(t, errs, nil) - errs = v1.Struct(val) - NotEqual(t, errs, nil) - Equal(t, len(errs.(ValidationErrors)), 2) - AssertError(t, errs, "TestStructReturnValidationErrors.Inner1.Inner2.String", "String", "required") - // this is an extra error reported from struct validation, it's a badly formatted one, but on purpose - AssertError(t, errs, "TestStructReturnValidationErrors.Inner1.String", "String", "required") - - fe, ok := errs.(ValidationErrors)["TestStructReturnValidationErrors.Inner1.Inner2.String"] - Equal(t, ok, true) - - // check for proper JSON namespace - Equal(t, fe.Field, "String") - Equal(t, fe.Name, "JSONString") - Equal(t, fe.FieldNamespace, "TestStructReturnValidationErrors.Inner1.Inner2.String") - Equal(t, fe.NameNamespace, "TestStructReturnValidationErrors.Inner1JSON.Inner2.JSONString") - - fe, ok = errs.(ValidationErrors)["TestStructReturnValidationErrors.Inner1.String"] - Equal(t, ok, true) - - // check for proper JSON namespace - Equal(t, fe.Field, "String") - Equal(t, fe.Name, "JSONString") - Equal(t, fe.FieldNamespace, "TestStructReturnValidationErrors.Inner1.String") - Equal(t, fe.NameNamespace, "TestStructReturnValidationErrors.Inner1JSON.JSONString") -} +// s = "rgb(255,255,0)" +// errs = validate.Field(s, "iscolor,len=5") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "len") -func TestStructLevelValidations(t *testing.T) { +// type Test struct { +// Color string `validate:"iscolor"` +// } - config := &Config{ - TagName: "validate", - } +// tst := &Test{ +// Color: "#000", +// } + +// errs = validate.Struct(tst) +// Equal(t, errs, nil) + +// tst.Color = "cfvre" +// errs = validate.Struct(tst) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "Test.Color", "Color", "iscolor") +// Equal(t, errs.(ValidationErrors)["Test.Color"].ActualTag, "hexcolor|rgb|rgba|hsl|hsla") + +// validate.RegisterAliasValidation("req", "required,dive,iscolor") +// arr := []string{"val1", "#fff", "#000"} + +// errs = validate.Field(arr, "req") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "[0]", "[0]", "iscolor") + +// PanicMatches(t, func() { validate.RegisterAliasValidation("exists", "gt=5,lt=10") }, "Alias 'exists' either contains restricted characters or is the same as a restricted tag needed for normal operation") +// } + +// 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) { + +// p1 := []string{ +// "NoTag", +// "Required", +// } + +// p2 := []string{ +// "SubSlice[0].Test", +// "Sub", +// "SubIgnore", +// "Anonymous.A", +// } + +// p3 := []string{ +// "SubTest.Test", +// } + +// p4 := []string{ +// "A", +// } + +// tPartial := &TestPartial{ +// NoTag: "NoTag", +// Required: "Required", + +// SubSlice: []*SubTest{ +// { + +// Test: "Required", +// }, +// { + +// Test: "Required", +// }, +// }, + +// Sub: &SubTest{ +// Test: "1", +// }, +// SubIgnore: &SubTest{ +// Test: "", +// }, +// Anonymous: struct { +// A string `validate:"required"` +// ASubSlice []*SubTest `validate:"required,dive"` +// SubAnonStruct []struct { +// Test string `validate:"required"` +// OtherTest string `validate:"required"` +// } `validate:"required,dive"` +// }{ +// A: "1", +// ASubSlice: []*SubTest{ +// { +// Test: "Required", +// }, +// { +// Test: "Required", +// }, +// }, + +// SubAnonStruct: []struct { +// Test string `validate:"required"` +// OtherTest string `validate:"required"` +// }{ +// {"Required", "RequiredOther"}, +// {"Required", "RequiredOther"}, +// }, +// }, +// } + +// // the following should all return no errors as everything is valid in +// // the default state +// errs := validate.StructPartial(tPartial, p1...) +// Equal(t, errs, nil) + +// errs = validate.StructPartial(tPartial, p2...) +// Equal(t, errs, nil) + +// // this isn't really a robust test, but is ment to illustrate the ANON CASE below +// errs = validate.StructPartial(tPartial.SubSlice[0], p3...) +// Equal(t, errs, nil) + +// errs = validate.StructExcept(tPartial, p1...) +// Equal(t, errs, nil) + +// errs = validate.StructExcept(tPartial, p2...) +// Equal(t, errs, nil) + +// // mod tParial for required feild and re-test making sure invalid fields are NOT required: +// tPartial.Required = "" + +// errs = validate.StructExcept(tPartial, p1...) +// Equal(t, errs, nil) + +// errs = validate.StructPartial(tPartial, p2...) +// Equal(t, errs, nil) + +// // inversion and retesting Partial to generate failures: +// errs = validate.StructPartial(tPartial, p1...) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "TestPartial.Required", "Required", "required") + +// errs = validate.StructExcept(tPartial, p2...) +// AssertError(t, errs, "TestPartial.Required", "Required", "required") + +// // reset Required field, and set nested struct +// tPartial.Required = "Required" +// tPartial.Anonymous.A = "" + +// // will pass as unset feilds is not going to be tested +// errs = validate.StructPartial(tPartial, p1...) +// Equal(t, errs, nil) + +// errs = validate.StructExcept(tPartial, p2...) +// Equal(t, errs, nil) + +// // ANON CASE the response here is strange, it clearly does what it is being told to +// errs = validate.StructExcept(tPartial.Anonymous, p4...) +// Equal(t, errs, nil) + +// // will fail as unset feild is tested +// errs = validate.StructPartial(tPartial, p2...) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "TestPartial.Anonymous.A", "A", "required") + +// errs = validate.StructExcept(tPartial, p1...) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "TestPartial.Anonymous.A", "A", "required") + +// // reset nested struct and unset struct in slice +// tPartial.Anonymous.A = "Required" +// tPartial.SubSlice[0].Test = "" + +// // these will pass as unset item is NOT tested +// errs = validate.StructPartial(tPartial, p1...) +// Equal(t, errs, nil) + +// errs = validate.StructExcept(tPartial, p2...) +// Equal(t, errs, nil) + +// // these will fail as unset item IS tested +// errs = validate.StructExcept(tPartial, p1...) +// AssertError(t, errs, "TestPartial.SubSlice[0].Test", "Test", "required") +// Equal(t, len(errs.(ValidationErrors)), 1) + +// errs = validate.StructPartial(tPartial, p2...) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "TestPartial.SubSlice[0].Test", "Test", "required") +// Equal(t, len(errs.(ValidationErrors)), 1) + +// // Unset second slice member concurrently to test dive behavior: +// tPartial.SubSlice[1].Test = "" + +// errs = validate.StructPartial(tPartial, p1...) +// Equal(t, errs, nil) + +// // NOTE: When specifying nested items, it is still the users responsibility +// // to specify the dive tag, the library does not override this. +// errs = validate.StructExcept(tPartial, p2...) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "TestPartial.SubSlice[1].Test", "Test", "required") + +// errs = validate.StructExcept(tPartial, p1...) +// Equal(t, len(errs.(ValidationErrors)), 2) +// AssertError(t, errs, "TestPartial.SubSlice[0].Test", "Test", "required") +// AssertError(t, errs, "TestPartial.SubSlice[1].Test", "Test", "required") + +// errs = validate.StructPartial(tPartial, p2...) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.(ValidationErrors)), 1) +// AssertError(t, errs, "TestPartial.SubSlice[0].Test", "Test", "required") + +// // reset struct in slice, and unset struct in slice in unset posistion +// tPartial.SubSlice[0].Test = "Required" + +// // these will pass as the unset item is NOT tested +// errs = validate.StructPartial(tPartial, p1...) +// Equal(t, errs, nil) + +// errs = validate.StructPartial(tPartial, p2...) +// Equal(t, errs, nil) + +// // testing for missing item by exception, yes it dives and fails +// errs = validate.StructExcept(tPartial, p1...) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.(ValidationErrors)), 1) +// AssertError(t, errs, "TestPartial.SubSlice[1].Test", "Test", "required") + +// errs = validate.StructExcept(tPartial, p2...) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "TestPartial.SubSlice[1].Test", "Test", "required") + +// tPartial.SubSlice[1].Test = "Required" + +// tPartial.Anonymous.SubAnonStruct[0].Test = "" +// // these will pass as the unset item is NOT tested +// errs = validate.StructPartial(tPartial, p1...) +// Equal(t, errs, nil) + +// errs = validate.StructPartial(tPartial, p2...) +// Equal(t, errs, nil) + +// errs = validate.StructExcept(tPartial, p1...) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "TestPartial.Anonymous.SubAnonStruct[0].Test", "Test", "required") + +// errs = validate.StructExcept(tPartial, p2...) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "TestPartial.Anonymous.SubAnonStruct[0].Test", "Test", "required") + +// } + +// func TestCrossStructLteFieldValidation(t *testing.T) { + +// type Inner struct { +// CreatedAt *time.Time +// String string +// Int int +// Uint uint +// Float float64 +// Array []string +// } + +// type Test struct { +// Inner *Inner +// CreatedAt *time.Time `validate:"ltecsfield=Inner.CreatedAt"` +// String string `validate:"ltecsfield=Inner.String"` +// Int int `validate:"ltecsfield=Inner.Int"` +// Uint uint `validate:"ltecsfield=Inner.Uint"` +// Float float64 `validate:"ltecsfield=Inner.Float"` +// Array []string `validate:"ltecsfield=Inner.Array"` +// } + +// now := time.Now().UTC() +// then := now.Add(time.Hour * 5) + +// inner := &Inner{ +// CreatedAt: &then, +// String: "abcd", +// Int: 13, +// Uint: 13, +// Float: 1.13, +// Array: []string{"val1", "val2"}, +// } + +// test := &Test{ +// Inner: inner, +// CreatedAt: &now, +// String: "abc", +// Int: 12, +// Uint: 12, +// Float: 1.12, +// Array: []string{"val1"}, +// } + +// errs := validate.Struct(test) +// Equal(t, errs, nil) + +// test.CreatedAt = &then +// test.String = "abcd" +// test.Int = 13 +// test.Uint = 13 +// test.Float = 1.13 +// test.Array = []string{"val1", "val2"} + +// errs = validate.Struct(test) +// Equal(t, errs, nil) + +// after := now.Add(time.Hour * 10) + +// test.CreatedAt = &after +// test.String = "abce" +// test.Int = 14 +// test.Uint = 14 +// test.Float = 1.14 +// test.Array = []string{"val1", "val2", "val3"} + +// errs = validate.Struct(test) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "Test.CreatedAt", "CreatedAt", "ltecsfield") +// AssertError(t, errs, "Test.String", "String", "ltecsfield") +// AssertError(t, errs, "Test.Int", "Int", "ltecsfield") +// AssertError(t, errs, "Test.Uint", "Uint", "ltecsfield") +// AssertError(t, errs, "Test.Float", "Float", "ltecsfield") +// AssertError(t, errs, "Test.Array", "Array", "ltecsfield") + +// errs = validate.FieldWithValue(1, "", "ltecsfield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "ltecsfield") + +// errs = validate.FieldWithValue(test, now, "ltecsfield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "ltecsfield") +// } + +// func TestCrossStructLtFieldValidation(t *testing.T) { + +// type Inner struct { +// CreatedAt *time.Time +// String string +// Int int +// Uint uint +// Float float64 +// Array []string +// } + +// type Test struct { +// Inner *Inner +// CreatedAt *time.Time `validate:"ltcsfield=Inner.CreatedAt"` +// String string `validate:"ltcsfield=Inner.String"` +// Int int `validate:"ltcsfield=Inner.Int"` +// Uint uint `validate:"ltcsfield=Inner.Uint"` +// Float float64 `validate:"ltcsfield=Inner.Float"` +// Array []string `validate:"ltcsfield=Inner.Array"` +// } + +// now := time.Now().UTC() +// then := now.Add(time.Hour * 5) + +// inner := &Inner{ +// CreatedAt: &then, +// String: "abcd", +// Int: 13, +// Uint: 13, +// Float: 1.13, +// Array: []string{"val1", "val2"}, +// } + +// test := &Test{ +// Inner: inner, +// CreatedAt: &now, +// String: "abc", +// Int: 12, +// Uint: 12, +// Float: 1.12, +// Array: []string{"val1"}, +// } + +// errs := validate.Struct(test) +// Equal(t, errs, nil) + +// test.CreatedAt = &then +// test.String = "abcd" +// test.Int = 13 +// test.Uint = 13 +// test.Float = 1.13 +// test.Array = []string{"val1", "val2"} + +// errs = validate.Struct(test) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "Test.CreatedAt", "CreatedAt", "ltcsfield") +// AssertError(t, errs, "Test.String", "String", "ltcsfield") +// AssertError(t, errs, "Test.Int", "Int", "ltcsfield") +// AssertError(t, errs, "Test.Uint", "Uint", "ltcsfield") +// AssertError(t, errs, "Test.Float", "Float", "ltcsfield") +// AssertError(t, errs, "Test.Array", "Array", "ltcsfield") + +// errs = validate.FieldWithValue(1, "", "ltcsfield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "ltcsfield") + +// errs = validate.FieldWithValue(test, now, "ltcsfield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "ltcsfield") +// } + +// func TestCrossStructGteFieldValidation(t *testing.T) { + +// type Inner struct { +// CreatedAt *time.Time +// String string +// Int int +// Uint uint +// Float float64 +// Array []string +// } + +// type Test struct { +// Inner *Inner +// CreatedAt *time.Time `validate:"gtecsfield=Inner.CreatedAt"` +// String string `validate:"gtecsfield=Inner.String"` +// Int int `validate:"gtecsfield=Inner.Int"` +// Uint uint `validate:"gtecsfield=Inner.Uint"` +// Float float64 `validate:"gtecsfield=Inner.Float"` +// Array []string `validate:"gtecsfield=Inner.Array"` +// } + +// now := time.Now().UTC() +// then := now.Add(time.Hour * -5) + +// inner := &Inner{ +// CreatedAt: &then, +// String: "abcd", +// Int: 13, +// Uint: 13, +// Float: 1.13, +// Array: []string{"val1", "val2"}, +// } + +// test := &Test{ +// Inner: inner, +// CreatedAt: &now, +// String: "abcde", +// Int: 14, +// Uint: 14, +// Float: 1.14, +// Array: []string{"val1", "val2", "val3"}, +// } + +// errs := validate.Struct(test) +// Equal(t, errs, nil) + +// test.CreatedAt = &then +// test.String = "abcd" +// test.Int = 13 +// test.Uint = 13 +// test.Float = 1.13 +// test.Array = []string{"val1", "val2"} + +// errs = validate.Struct(test) +// Equal(t, errs, nil) + +// before := now.Add(time.Hour * -10) + +// test.CreatedAt = &before +// test.String = "abc" +// test.Int = 12 +// test.Uint = 12 +// test.Float = 1.12 +// test.Array = []string{"val1"} + +// errs = validate.Struct(test) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "Test.CreatedAt", "CreatedAt", "gtecsfield") +// AssertError(t, errs, "Test.String", "String", "gtecsfield") +// AssertError(t, errs, "Test.Int", "Int", "gtecsfield") +// AssertError(t, errs, "Test.Uint", "Uint", "gtecsfield") +// AssertError(t, errs, "Test.Float", "Float", "gtecsfield") +// AssertError(t, errs, "Test.Array", "Array", "gtecsfield") + +// errs = validate.FieldWithValue(1, "", "gtecsfield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "gtecsfield") + +// errs = validate.FieldWithValue(test, now, "gtecsfield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "gtecsfield") +// } + +// func TestCrossStructGtFieldValidation(t *testing.T) { + +// type Inner struct { +// CreatedAt *time.Time +// String string +// Int int +// Uint uint +// Float float64 +// Array []string +// } + +// type Test struct { +// Inner *Inner +// CreatedAt *time.Time `validate:"gtcsfield=Inner.CreatedAt"` +// String string `validate:"gtcsfield=Inner.String"` +// Int int `validate:"gtcsfield=Inner.Int"` +// Uint uint `validate:"gtcsfield=Inner.Uint"` +// Float float64 `validate:"gtcsfield=Inner.Float"` +// Array []string `validate:"gtcsfield=Inner.Array"` +// } + +// now := time.Now().UTC() +// then := now.Add(time.Hour * -5) + +// inner := &Inner{ +// CreatedAt: &then, +// String: "abcd", +// Int: 13, +// Uint: 13, +// Float: 1.13, +// Array: []string{"val1", "val2"}, +// } + +// test := &Test{ +// Inner: inner, +// CreatedAt: &now, +// String: "abcde", +// Int: 14, +// Uint: 14, +// Float: 1.14, +// Array: []string{"val1", "val2", "val3"}, +// } + +// errs := validate.Struct(test) +// Equal(t, errs, nil) + +// test.CreatedAt = &then +// test.String = "abcd" +// test.Int = 13 +// test.Uint = 13 +// test.Float = 1.13 +// test.Array = []string{"val1", "val2"} + +// errs = validate.Struct(test) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "Test.CreatedAt", "CreatedAt", "gtcsfield") +// AssertError(t, errs, "Test.String", "String", "gtcsfield") +// AssertError(t, errs, "Test.Int", "Int", "gtcsfield") +// AssertError(t, errs, "Test.Uint", "Uint", "gtcsfield") +// AssertError(t, errs, "Test.Float", "Float", "gtcsfield") +// AssertError(t, errs, "Test.Array", "Array", "gtcsfield") + +// errs = validate.FieldWithValue(1, "", "gtcsfield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "gtcsfield") + +// errs = validate.FieldWithValue(test, now, "gtcsfield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "gtcsfield") +// } + +// func TestCrossStructNeFieldValidation(t *testing.T) { + +// type Inner struct { +// CreatedAt *time.Time +// } + +// type Test struct { +// Inner *Inner +// CreatedAt *time.Time `validate:"necsfield=Inner.CreatedAt"` +// } + +// now := time.Now().UTC() +// then := now.Add(time.Hour * 5) + +// inner := &Inner{ +// CreatedAt: &then, +// } + +// test := &Test{ +// Inner: inner, +// CreatedAt: &now, +// } + +// errs := validate.Struct(test) +// Equal(t, errs, nil) + +// test.CreatedAt = &then + +// errs = validate.Struct(test) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "Test.CreatedAt", "CreatedAt", "necsfield") + +// var j uint64 +// var k float64 +// var j2 uint64 +// var k2 float64 +// s := "abcd" +// i := 1 +// j = 1 +// k = 1.543 +// arr := []string{"test"} + +// s2 := "abcd" +// i2 := 1 +// j2 = 1 +// k2 = 1.543 +// arr2 := []string{"test"} +// arr3 := []string{"test", "test2"} +// now2 := now + +// errs = validate.FieldWithValue(s, s2, "necsfield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "necsfield") + +// errs = validate.FieldWithValue(i2, i, "necsfield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "necsfield") + +// errs = validate.FieldWithValue(j2, j, "necsfield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "necsfield") + +// errs = validate.FieldWithValue(k2, k, "necsfield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "necsfield") + +// errs = validate.FieldWithValue(arr2, arr, "necsfield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "necsfield") + +// errs = validate.FieldWithValue(now2, now, "necsfield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "necsfield") + +// errs = validate.FieldWithValue(arr3, arr, "necsfield") +// Equal(t, errs, nil) + +// type SInner struct { +// Name string +// } + +// type TStruct struct { +// Inner *SInner +// CreatedAt *time.Time `validate:"necsfield=Inner"` +// } + +// sinner := &SInner{ +// Name: "NAME", +// } + +// test2 := &TStruct{ +// Inner: sinner, +// CreatedAt: &now, +// } + +// errs = validate.Struct(test2) +// Equal(t, errs, nil) + +// test2.Inner = nil +// errs = validate.Struct(test2) +// Equal(t, errs, nil) + +// errs = validate.FieldWithValue(nil, 1, "necsfield") +// Equal(t, errs, nil) +// } + +// func TestCrossStructEqFieldValidation(t *testing.T) { + +// type Inner struct { +// CreatedAt *time.Time +// } + +// type Test struct { +// Inner *Inner +// CreatedAt *time.Time `validate:"eqcsfield=Inner.CreatedAt"` +// } + +// now := time.Now().UTC() + +// inner := &Inner{ +// CreatedAt: &now, +// } + +// test := &Test{ +// Inner: inner, +// CreatedAt: &now, +// } + +// errs := validate.Struct(test) +// Equal(t, errs, nil) + +// newTime := time.Now().UTC() +// test.CreatedAt = &newTime + +// errs = validate.Struct(test) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "Test.CreatedAt", "CreatedAt", "eqcsfield") + +// var j uint64 +// var k float64 +// s := "abcd" +// i := 1 +// j = 1 +// k = 1.543 +// arr := []string{"test"} + +// var j2 uint64 +// var k2 float64 +// s2 := "abcd" +// i2 := 1 +// j2 = 1 +// k2 = 1.543 +// arr2 := []string{"test"} +// arr3 := []string{"test", "test2"} +// now2 := now + +// errs = validate.FieldWithValue(s, s2, "eqcsfield") +// Equal(t, errs, nil) + +// errs = validate.FieldWithValue(i2, i, "eqcsfield") +// Equal(t, errs, nil) + +// errs = validate.FieldWithValue(j2, j, "eqcsfield") +// Equal(t, errs, nil) + +// errs = validate.FieldWithValue(k2, k, "eqcsfield") +// Equal(t, errs, nil) + +// errs = validate.FieldWithValue(arr2, arr, "eqcsfield") +// Equal(t, errs, nil) + +// errs = validate.FieldWithValue(now2, now, "eqcsfield") +// Equal(t, errs, nil) + +// errs = validate.FieldWithValue(arr3, arr, "eqcsfield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "eqcsfield") + +// type SInner struct { +// Name string +// } + +// type TStruct struct { +// Inner *SInner +// CreatedAt *time.Time `validate:"eqcsfield=Inner"` +// } + +// sinner := &SInner{ +// Name: "NAME", +// } + +// test2 := &TStruct{ +// Inner: sinner, +// CreatedAt: &now, +// } + +// errs = validate.Struct(test2) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "TStruct.CreatedAt", "CreatedAt", "eqcsfield") + +// test2.Inner = nil +// errs = validate.Struct(test2) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "TStruct.CreatedAt", "CreatedAt", "eqcsfield") + +// errs = validate.FieldWithValue(nil, 1, "eqcsfield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "eqcsfield") +// } + +// func TestCrossNamespaceFieldValidation(t *testing.T) { + +// type SliceStruct struct { +// Name string +// } + +// type MapStruct struct { +// Name string +// } + +// type Inner struct { +// CreatedAt *time.Time +// Slice []string +// SliceStructs []*SliceStruct +// SliceSlice [][]string +// SliceSliceStruct [][]*SliceStruct +// SliceMap []map[string]string +// Map map[string]string +// MapMap map[string]map[string]string +// MapStructs map[string]*SliceStruct +// MapMapStruct map[string]map[string]*SliceStruct +// MapSlice map[string][]string +// MapInt map[int]string +// MapInt8 map[int8]string +// MapInt16 map[int16]string +// MapInt32 map[int32]string +// MapInt64 map[int64]string +// MapUint map[uint]string +// MapUint8 map[uint8]string +// MapUint16 map[uint16]string +// MapUint32 map[uint32]string +// MapUint64 map[uint64]string +// MapFloat32 map[float32]string +// MapFloat64 map[float64]string +// MapBool map[bool]string +// } + +// type Test struct { +// Inner *Inner +// CreatedAt *time.Time +// } + +// now := time.Now() + +// inner := &Inner{ +// CreatedAt: &now, +// Slice: []string{"val1", "val2", "val3"}, +// SliceStructs: []*SliceStruct{{Name: "name1"}, {Name: "name2"}, {Name: "name3"}}, +// SliceSlice: [][]string{{"1", "2", "3"}, {"4", "5", "6"}, {"7", "8", "9"}}, +// SliceSliceStruct: [][]*SliceStruct{{{Name: "name1"}, {Name: "name2"}, {Name: "name3"}}, {{Name: "name4"}, {Name: "name5"}, {Name: "name6"}}, {{Name: "name7"}, {Name: "name8"}, {Name: "name9"}}}, +// SliceMap: []map[string]string{{"key1": "val1", "key2": "val2", "key3": "val3"}, {"key4": "val4", "key5": "val5", "key6": "val6"}}, +// Map: map[string]string{"key1": "val1", "key2": "val2", "key3": "val3"}, +// MapStructs: map[string]*SliceStruct{"key1": {Name: "name1"}, "key2": {Name: "name2"}, "key3": {Name: "name3"}}, +// MapMap: map[string]map[string]string{"key1": {"key1-1": "val1"}, "key2": {"key2-1": "val2"}, "key3": {"key3-1": "val3"}}, +// MapMapStruct: map[string]map[string]*SliceStruct{"key1": {"key1-1": {Name: "name1"}}, "key2": {"key2-1": {Name: "name2"}}, "key3": {"key3-1": {Name: "name3"}}}, +// MapSlice: map[string][]string{"key1": {"1", "2", "3"}, "key2": {"4", "5", "6"}, "key3": {"7", "8", "9"}}, +// MapInt: map[int]string{1: "val1", 2: "val2", 3: "val3"}, +// MapInt8: map[int8]string{1: "val1", 2: "val2", 3: "val3"}, +// MapInt16: map[int16]string{1: "val1", 2: "val2", 3: "val3"}, +// MapInt32: map[int32]string{1: "val1", 2: "val2", 3: "val3"}, +// MapInt64: map[int64]string{1: "val1", 2: "val2", 3: "val3"}, +// MapUint: map[uint]string{1: "val1", 2: "val2", 3: "val3"}, +// MapUint8: map[uint8]string{1: "val1", 2: "val2", 3: "val3"}, +// MapUint16: map[uint16]string{1: "val1", 2: "val2", 3: "val3"}, +// MapUint32: map[uint32]string{1: "val1", 2: "val2", 3: "val3"}, +// MapUint64: map[uint64]string{1: "val1", 2: "val2", 3: "val3"}, +// MapFloat32: map[float32]string{1.01: "val1", 2.02: "val2", 3.03: "val3"}, +// MapFloat64: map[float64]string{1.01: "val1", 2.02: "val2", 3.03: "val3"}, +// MapBool: map[bool]string{true: "val1", false: "val2"}, +// } + +// test := &Test{ +// Inner: inner, +// CreatedAt: &now, +// } + +// val := reflect.ValueOf(test) + +// current, kind, ok := validate.GetStructFieldOK(val, "Inner.CreatedAt") +// Equal(t, ok, true) +// Equal(t, kind, reflect.Struct) +// tm, ok := current.Interface().(time.Time) +// Equal(t, ok, true) +// Equal(t, tm, now) + +// current, kind, ok = validate.GetStructFieldOK(val, "Inner.Slice[1]") +// Equal(t, ok, true) +// Equal(t, kind, reflect.String) +// Equal(t, current.String(), "val2") + +// current, kind, ok = validate.GetStructFieldOK(val, "Inner.CrazyNonExistantField") +// Equal(t, ok, false) + +// current, kind, ok = validate.GetStructFieldOK(val, "Inner.Slice[101]") +// Equal(t, ok, false) + +// current, kind, ok = validate.GetStructFieldOK(val, "Inner.Map[key3]") +// Equal(t, ok, true) +// Equal(t, kind, reflect.String) +// Equal(t, current.String(), "val3") + +// current, kind, ok = validate.GetStructFieldOK(val, "Inner.MapMap[key2][key2-1]") +// Equal(t, ok, true) +// Equal(t, kind, reflect.String) +// Equal(t, current.String(), "val2") + +// current, kind, ok = validate.GetStructFieldOK(val, "Inner.MapStructs[key2].Name") +// Equal(t, ok, true) +// Equal(t, kind, reflect.String) +// Equal(t, current.String(), "name2") + +// current, kind, ok = validate.GetStructFieldOK(val, "Inner.MapMapStruct[key3][key3-1].Name") +// Equal(t, ok, true) +// Equal(t, kind, reflect.String) +// Equal(t, current.String(), "name3") + +// current, kind, ok = validate.GetStructFieldOK(val, "Inner.SliceSlice[2][0]") +// Equal(t, ok, true) +// Equal(t, kind, reflect.String) +// Equal(t, current.String(), "7") + +// current, kind, ok = validate.GetStructFieldOK(val, "Inner.SliceSliceStruct[2][1].Name") +// Equal(t, ok, true) +// Equal(t, kind, reflect.String) +// Equal(t, current.String(), "name8") + +// current, kind, ok = validate.GetStructFieldOK(val, "Inner.SliceMap[1][key5]") +// Equal(t, ok, true) +// Equal(t, kind, reflect.String) +// Equal(t, current.String(), "val5") + +// current, kind, ok = validate.GetStructFieldOK(val, "Inner.MapSlice[key3][2]") +// Equal(t, ok, true) +// Equal(t, kind, reflect.String) +// Equal(t, current.String(), "9") + +// current, kind, ok = validate.GetStructFieldOK(val, "Inner.MapInt[2]") +// Equal(t, ok, true) +// Equal(t, kind, reflect.String) +// Equal(t, current.String(), "val2") + +// current, kind, ok = validate.GetStructFieldOK(val, "Inner.MapInt8[2]") +// Equal(t, ok, true) +// Equal(t, kind, reflect.String) +// Equal(t, current.String(), "val2") + +// current, kind, ok = validate.GetStructFieldOK(val, "Inner.MapInt16[2]") +// Equal(t, ok, true) +// Equal(t, kind, reflect.String) +// Equal(t, current.String(), "val2") + +// current, kind, ok = validate.GetStructFieldOK(val, "Inner.MapInt32[2]") +// Equal(t, ok, true) +// Equal(t, kind, reflect.String) +// Equal(t, current.String(), "val2") + +// current, kind, ok = validate.GetStructFieldOK(val, "Inner.MapInt64[2]") +// Equal(t, ok, true) +// Equal(t, kind, reflect.String) +// Equal(t, current.String(), "val2") + +// current, kind, ok = validate.GetStructFieldOK(val, "Inner.MapUint[2]") +// Equal(t, ok, true) +// Equal(t, kind, reflect.String) +// Equal(t, current.String(), "val2") + +// current, kind, ok = validate.GetStructFieldOK(val, "Inner.MapUint8[2]") +// Equal(t, ok, true) +// Equal(t, kind, reflect.String) +// Equal(t, current.String(), "val2") + +// current, kind, ok = validate.GetStructFieldOK(val, "Inner.MapUint16[2]") +// Equal(t, ok, true) +// Equal(t, kind, reflect.String) +// Equal(t, current.String(), "val2") + +// current, kind, ok = validate.GetStructFieldOK(val, "Inner.MapUint32[2]") +// Equal(t, ok, true) +// Equal(t, kind, reflect.String) +// Equal(t, current.String(), "val2") + +// current, kind, ok = validate.GetStructFieldOK(val, "Inner.MapUint64[2]") +// Equal(t, ok, true) +// Equal(t, kind, reflect.String) +// Equal(t, current.String(), "val2") + +// current, kind, ok = validate.GetStructFieldOK(val, "Inner.MapFloat32[3.03]") +// Equal(t, ok, true) +// Equal(t, kind, reflect.String) +// Equal(t, current.String(), "val3") + +// current, kind, ok = validate.GetStructFieldOK(val, "Inner.MapFloat64[2.02]") +// Equal(t, ok, true) +// Equal(t, kind, reflect.String) +// Equal(t, current.String(), "val2") + +// current, kind, ok = validate.GetStructFieldOK(val, "Inner.MapBool[true]") +// Equal(t, ok, true) +// Equal(t, kind, reflect.String) +// Equal(t, current.String(), "val1") + +// inner = &Inner{ +// CreatedAt: &now, +// Slice: []string{"val1", "val2", "val3"}, +// SliceStructs: []*SliceStruct{{Name: "name1"}, {Name: "name2"}, nil}, +// SliceSlice: [][]string{{"1", "2", "3"}, {"4", "5", "6"}, {"7", "8", "9"}}, +// SliceSliceStruct: [][]*SliceStruct{{{Name: "name1"}, {Name: "name2"}, {Name: "name3"}}, {{Name: "name4"}, {Name: "name5"}, {Name: "name6"}}, {{Name: "name7"}, {Name: "name8"}, {Name: "name9"}}}, +// SliceMap: []map[string]string{{"key1": "val1", "key2": "val2", "key3": "val3"}, {"key4": "val4", "key5": "val5", "key6": "val6"}}, +// Map: map[string]string{"key1": "val1", "key2": "val2", "key3": "val3"}, +// MapStructs: map[string]*SliceStruct{"key1": {Name: "name1"}, "key2": {Name: "name2"}, "key3": {Name: "name3"}}, +// MapMap: map[string]map[string]string{"key1": {"key1-1": "val1"}, "key2": {"key2-1": "val2"}, "key3": {"key3-1": "val3"}}, +// MapMapStruct: map[string]map[string]*SliceStruct{"key1": {"key1-1": {Name: "name1"}}, "key2": {"key2-1": {Name: "name2"}}, "key3": {"key3-1": {Name: "name3"}}}, +// MapSlice: map[string][]string{"key1": {"1", "2", "3"}, "key2": {"4", "5", "6"}, "key3": {"7", "8", "9"}}, +// } + +// test = &Test{ +// Inner: inner, +// CreatedAt: nil, +// } + +// val = reflect.ValueOf(test) + +// current, kind, ok = validate.GetStructFieldOK(val, "Inner.SliceStructs[2]") +// Equal(t, ok, true) +// Equal(t, kind, reflect.Ptr) +// Equal(t, current.String(), "<*validator.SliceStruct Value>") +// Equal(t, current.IsNil(), true) + +// current, kind, ok = validate.GetStructFieldOK(val, "Inner.SliceStructs[2].Name") +// Equal(t, ok, false) +// Equal(t, kind, reflect.Ptr) +// Equal(t, current.String(), "<*validator.SliceStruct Value>") +// Equal(t, current.IsNil(), true) + +// PanicMatches(t, func() { validate.GetStructFieldOK(reflect.ValueOf(1), "crazyinput") }, "Invalid field namespace") +// } + +// func TestExistsValidation(t *testing.T) { + +// jsonText := "{ \"truthiness2\": true }" + +// type Thing struct { +// Truthiness *bool `json:"truthiness" validate:"exists,required"` +// } + +// var ting Thing + +// err := json.Unmarshal([]byte(jsonText), &ting) +// Equal(t, err, nil) +// NotEqual(t, ting, nil) +// Equal(t, ting.Truthiness, nil) + +// errs := validate.Struct(ting) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "Thing.Truthiness", "Truthiness", "exists") - v1 := New(config) - v1.RegisterStructValidation(StructValidationTestStruct, TestStruct{}) +// jsonText = "{ \"truthiness\": true }" - tst := &TestStruct{ - String: "good value", - } +// err = json.Unmarshal([]byte(jsonText), &ting) +// Equal(t, err, nil) +// NotEqual(t, ting, nil) +// Equal(t, ting.Truthiness, true) - errs := v1.Struct(tst) - NotEqual(t, errs, nil) - AssertError(t, errs, "TestStruct.String", "String", "badvalueteststruct") +// errs = validate.Struct(ting) +// Equal(t, errs, nil) +// } - v2 := New(config) - v2.RegisterStructValidation(StructValidationBadTestStructFieldName, TestStruct{}) +// func TestSQLValue2Validation(t *testing.T) { - PanicMatches(t, func() { v2.Struct(tst) }, fieldNameRequired) +// config := &Config{ +// TagName: "validate", +// } - v3 := New(config) - v3.RegisterStructValidation(StructValidationBadTestStructTag, TestStruct{}) +// validate := New(config) +// validate.RegisterCustomTypeFunc(ValidateValuerType, valuer{}, (*driver.Valuer)(nil), sql.NullString{}, sql.NullInt64{}, sql.NullBool{}, sql.NullFloat64{}) +// validate.RegisterCustomTypeFunc(ValidateCustomType, MadeUpCustomType{}) +// validate.RegisterCustomTypeFunc(OverrideIntTypeForSomeReason, 1) - PanicMatches(t, func() { v3.Struct(tst) }, tagRequired) +// val := valuer{ +// Name: "", +// } - v4 := New(config) - v4.RegisterStructValidation(StructValidationNoTestStructCustomName, TestStruct{}) +// errs := validate.Field(val, "required") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "required") - errs = v4.Struct(tst) - NotEqual(t, errs, nil) - AssertError(t, errs, "TestStruct.String", "String", "badvalueteststruct") +// val.Name = "Valid Name" +// errs = validate.Field(val, "required") +// Equal(t, errs, nil) + +// val.Name = "errorme" + +// PanicMatches(t, func() { validate.Field(val, "required") }, "SQL Driver Valuer error: some kind of error") - v5 := New(config) - v5.RegisterStructValidation(StructValidationTestStructInvalid, TestStruct{}) +// type myValuer valuer - errs = v5.Struct(tst) - NotEqual(t, errs, nil) - AssertError(t, errs, "TestStruct.String", "String", "badvalueteststruct") +// myVal := valuer{ +// Name: "", +// } - v6 := New(config) - v6.RegisterStructValidation(StructValidationTestStructSuccess, TestStruct{}) +// errs = validate.Field(myVal, "required") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "required") + +// cust := MadeUpCustomType{ +// FirstName: "Joey", +// LastName: "Bloggs", +// } + +// c := CustomMadeUpStruct{MadeUp: cust, OverriddenInt: 2} + +// errs = validate.Struct(c) +// Equal(t, errs, nil) - errs = v6.Struct(tst) - Equal(t, errs, nil) -} +// c.MadeUp.FirstName = "" +// c.OverriddenInt = 1 + +// errs = validate.Struct(c) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.(ValidationErrors)), 2) +// AssertError(t, errs, "CustomMadeUpStruct.MadeUp", "MadeUp", "required") +// AssertError(t, errs, "CustomMadeUpStruct.OverriddenInt", "OverriddenInt", "gt") +// } + +// func TestSQLValueValidation(t *testing.T) { + +// validate := New(&Config{TagName: "validate"}) +// validate.RegisterCustomTypeFunc(ValidateValuerType, (*driver.Valuer)(nil), valuer{}) +// validate.RegisterCustomTypeFunc(ValidateCustomType, MadeUpCustomType{}) +// validate.RegisterCustomTypeFunc(OverrideIntTypeForSomeReason, 1) + +// val := valuer{ +// Name: "", +// } + +// errs := validate.Field(val, "required") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "required") + +// val.Name = "Valid Name" +// errs = validate.Field(val, "required") +// Equal(t, errs, nil) + +// val.Name = "errorme" + +// PanicMatches(t, func() { errs = validate.Field(val, "required") }, "SQL Driver Valuer error: some kind of error") + +// type myValuer valuer + +// myVal := valuer{ +// Name: "", +// } + +// errs = validate.Field(myVal, "required") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "required") + +// cust := MadeUpCustomType{ +// FirstName: "Joey", +// LastName: "Bloggs", +// } + +// c := CustomMadeUpStruct{MadeUp: cust, OverriddenInt: 2} + +// errs = validate.Struct(c) +// Equal(t, errs, nil) + +// c.MadeUp.FirstName = "" +// c.OverriddenInt = 1 + +// errs = validate.Struct(c) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.(ValidationErrors)), 2) +// AssertError(t, errs, "CustomMadeUpStruct.MadeUp", "MadeUp", "required") +// AssertError(t, errs, "CustomMadeUpStruct.OverriddenInt", "OverriddenInt", "gt") +// } + +// func TestMACValidation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"3D:F2:C9:A6:B3:4F", true}, +// {"3D-F2-C9-A6-B3:4F", false}, +// {"123", false}, +// {"", false}, +// {"abacaba", false}, +// {"00:25:96:FF:FE:12:34:56", true}, +// {"0025:96FF:FE12:3456", false}, +// } + +// for i, test := range tests { + +// errs := validate.Field(test.param, "mac") + +// if test.expected { +// if !IsEqual(errs, nil) { +// t.Fatalf("Index: %d mac failed Error: %s", i, errs) +// } +// } else { +// if IsEqual(errs, nil) { +// t.Fatalf("Index: %d mac failed Error: %s", i, errs) +// } else { +// val := errs.(ValidationErrors)[""] +// if val.Tag != "mac" { +// t.Fatalf("Index: %d mac failed Error: %s", i, errs) +// } +// } +// } +// } +// } + +// func TestIPValidation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"", false}, +// {"10.0.0.1", true}, +// {"172.16.0.1", true}, +// {"192.168.0.1", true}, +// {"192.168.255.254", true}, +// {"192.168.255.256", false}, +// {"172.16.255.254", true}, +// {"172.16.256.255", false}, +// {"2001:cdba:0000:0000:0000:0000:3257:9652", true}, +// {"2001:cdba:0:0:0:0:3257:9652", true}, +// {"2001:cdba::3257:9652", true}, +// } + +// for i, test := range tests { + +// errs := validate.Field(test.param, "ip") + +// if test.expected { +// if !IsEqual(errs, nil) { +// t.Fatalf("Index: %d ip failed Error: %s", i, errs) +// } +// } else { +// if IsEqual(errs, nil) { +// t.Fatalf("Index: %d ip failed Error: %s", i, errs) +// } else { +// val := errs.(ValidationErrors)[""] +// if val.Tag != "ip" { +// t.Fatalf("Index: %d ip failed Error: %s", i, errs) +// } +// } +// } +// } +// } + +// func TestIPv6Validation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"10.0.0.1", false}, +// {"172.16.0.1", false}, +// {"192.168.0.1", false}, +// {"192.168.255.254", false}, +// {"192.168.255.256", false}, +// {"172.16.255.254", false}, +// {"172.16.256.255", false}, +// {"2001:cdba:0000:0000:0000:0000:3257:9652", true}, +// {"2001:cdba:0:0:0:0:3257:9652", true}, +// {"2001:cdba::3257:9652", true}, +// } + +// for i, test := range tests { + +// errs := validate.Field(test.param, "ipv6") + +// if test.expected { +// if !IsEqual(errs, nil) { +// t.Fatalf("Index: %d ipv6 failed Error: %s", i, errs) +// } +// } else { +// if IsEqual(errs, nil) { +// t.Fatalf("Index: %d ipv6 failed Error: %s", i, errs) +// } else { +// val := errs.(ValidationErrors)[""] +// if val.Tag != "ipv6" { +// t.Fatalf("Index: %d ipv6 failed Error: %s", i, errs) +// } +// } +// } +// } +// } + +// func TestIPv4Validation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"10.0.0.1", true}, +// {"172.16.0.1", true}, +// {"192.168.0.1", true}, +// {"192.168.255.254", true}, +// {"192.168.255.256", false}, +// {"172.16.255.254", true}, +// {"172.16.256.255", false}, +// {"2001:cdba:0000:0000:0000:0000:3257:9652", false}, +// {"2001:cdba:0:0:0:0:3257:9652", false}, +// {"2001:cdba::3257:9652", false}, +// } + +// for i, test := range tests { + +// errs := validate.Field(test.param, "ipv4") + +// if test.expected { +// if !IsEqual(errs, nil) { +// t.Fatalf("Index: %d ipv4 failed Error: %s", i, errs) +// } +// } else { +// if IsEqual(errs, nil) { +// t.Fatalf("Index: %d ipv4 failed Error: %s", i, errs) +// } else { +// val := errs.(ValidationErrors)[""] +// if val.Tag != "ipv4" { +// t.Fatalf("Index: %d ipv4 failed Error: %s", i, errs) +// } +// } +// } +// } +// } + +// func TestCIDRValidation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"10.0.0.0/0", true}, +// {"10.0.0.1/8", true}, +// {"172.16.0.1/16", true}, +// {"192.168.0.1/24", true}, +// {"192.168.255.254/24", true}, +// {"192.168.255.254/48", false}, +// {"192.168.255.256/24", false}, +// {"172.16.255.254/16", true}, +// {"172.16.256.255/16", false}, +// {"2001:cdba:0000:0000:0000:0000:3257:9652/64", true}, +// {"2001:cdba:0000:0000:0000:0000:3257:9652/256", false}, +// {"2001:cdba:0:0:0:0:3257:9652/32", true}, +// {"2001:cdba::3257:9652/16", true}, +// } + +// for i, test := range tests { + +// errs := validate.Field(test.param, "cidr") + +// if test.expected { +// if !IsEqual(errs, nil) { +// t.Fatalf("Index: %d cidr failed Error: %s", i, errs) +// } +// } else { +// if IsEqual(errs, nil) { +// t.Fatalf("Index: %d cidr failed Error: %s", i, errs) +// } else { +// val := errs.(ValidationErrors)[""] +// if val.Tag != "cidr" { +// t.Fatalf("Index: %d cidr failed Error: %s", i, errs) +// } +// } +// } +// } +// } + +// func TestCIDRv6Validation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"10.0.0.0/0", false}, +// {"10.0.0.1/8", false}, +// {"172.16.0.1/16", false}, +// {"192.168.0.1/24", false}, +// {"192.168.255.254/24", false}, +// {"192.168.255.254/48", false}, +// {"192.168.255.256/24", false}, +// {"172.16.255.254/16", false}, +// {"172.16.256.255/16", false}, +// {"2001:cdba:0000:0000:0000:0000:3257:9652/64", true}, +// {"2001:cdba:0000:0000:0000:0000:3257:9652/256", false}, +// {"2001:cdba:0:0:0:0:3257:9652/32", true}, +// {"2001:cdba::3257:9652/16", true}, +// } + +// for i, test := range tests { + +// errs := validate.Field(test.param, "cidrv6") + +// if test.expected { +// if !IsEqual(errs, nil) { +// t.Fatalf("Index: %d cidrv6 failed Error: %s", i, errs) +// } +// } else { +// if IsEqual(errs, nil) { +// t.Fatalf("Index: %d cidrv6 failed Error: %s", i, errs) +// } else { +// val := errs.(ValidationErrors)[""] +// if val.Tag != "cidrv6" { +// t.Fatalf("Index: %d cidrv6 failed Error: %s", i, errs) +// } +// } +// } +// } +// } + +// func TestCIDRv4Validation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"10.0.0.0/0", true}, +// {"10.0.0.1/8", true}, +// {"172.16.0.1/16", true}, +// {"192.168.0.1/24", true}, +// {"192.168.255.254/24", true}, +// {"192.168.255.254/48", false}, +// {"192.168.255.256/24", false}, +// {"172.16.255.254/16", true}, +// {"172.16.256.255/16", false}, +// {"2001:cdba:0000:0000:0000:0000:3257:9652/64", false}, +// {"2001:cdba:0000:0000:0000:0000:3257:9652/256", false}, +// {"2001:cdba:0:0:0:0:3257:9652/32", false}, +// {"2001:cdba::3257:9652/16", false}, +// } + +// for i, test := range tests { + +// errs := validate.Field(test.param, "cidrv4") + +// if test.expected { +// if !IsEqual(errs, nil) { +// t.Fatalf("Index: %d cidrv4 failed Error: %s", i, errs) +// } +// } else { +// if IsEqual(errs, nil) { +// t.Fatalf("Index: %d cidrv4 failed Error: %s", i, errs) +// } else { +// val := errs.(ValidationErrors)[""] +// if val.Tag != "cidrv4" { +// t.Fatalf("Index: %d cidrv4 failed Error: %s", i, errs) +// } +// } +// } +// } +// } + +// func TestTCPAddrValidation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"", false}, +// {":80", false}, +// {"127.0.0.1:80", true}, +// {"[::1]:80", true}, +// {"256.0.0.0:1", false}, +// {"[::1]", false}, +// } + +// for i, test := range tests { +// errs := validate.Field(test.param, "tcp_addr") +// if test.expected { +// if !IsEqual(errs, nil) { +// t.Fatalf("Index: %d tcp_addr failed Error: %s", i, errs) +// } +// } else { +// if IsEqual(errs, nil) { +// t.Fatalf("Index: %d tcp_addr failed Error: %s", i, errs) +// } else { +// val := errs.(ValidationErrors)[""] +// if val.Tag != "tcp_addr" { +// t.Fatalf("Index: %d tcp_addr failed Error: %s", i, errs) +// } +// } +// } +// } +// } + +// func TestTCP6AddrValidation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"", false}, +// {":80", false}, +// {"127.0.0.1:80", false}, +// {"[::1]:80", true}, +// {"256.0.0.0:1", false}, +// {"[::1]", false}, +// } + +// for i, test := range tests { +// errs := validate.Field(test.param, "tcp6_addr") +// if test.expected { +// if !IsEqual(errs, nil) { +// t.Fatalf("Index: %d tcp6_addr failed Error: %s", i, errs) +// } +// } else { +// if IsEqual(errs, nil) { +// t.Fatalf("Index: %d tcp6_addr failed Error: %s", i, errs) +// } else { +// val := errs.(ValidationErrors)[""] +// if val.Tag != "tcp6_addr" { +// t.Fatalf("Index: %d tcp6_addr failed Error: %s", i, errs) +// } +// } +// } +// } +// } + +// func TestTCP4AddrValidation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"", false}, +// {":80", false}, +// {"127.0.0.1:80", true}, +// {"[::1]:80", false}, // https://github.com/golang/go/issues/14037 +// {"256.0.0.0:1", false}, +// {"[::1]", false}, +// } + +// for i, test := range tests { +// errs := validate.Field(test.param, "tcp4_addr") +// if test.expected { +// if !IsEqual(errs, nil) { +// t.Fatalf("Index: %d tcp4_addr failed Error: %s", i, errs) +// } +// } else { +// if IsEqual(errs, nil) { +// t.Log(test.param, IsEqual(errs, nil)) +// t.Fatalf("Index: %d tcp4_addr failed Error: %s", i, errs) +// } else { +// val := errs.(ValidationErrors)[""] +// if val.Tag != "tcp4_addr" { +// t.Fatalf("Index: %d tcp4_addr failed Error: %s", i, errs) +// } +// } +// } +// } +// } + +// func TestUDPAddrValidation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"", false}, +// {":80", false}, +// {"127.0.0.1:80", true}, +// {"[::1]:80", true}, +// {"256.0.0.0:1", false}, +// {"[::1]", false}, +// } + +// for i, test := range tests { +// errs := validate.Field(test.param, "udp_addr") +// if test.expected { +// if !IsEqual(errs, nil) { +// t.Fatalf("Index: %d udp_addr failed Error: %s", i, errs) +// } +// } else { +// if IsEqual(errs, nil) { +// t.Fatalf("Index: %d udp_addr failed Error: %s", i, errs) +// } else { +// val := errs.(ValidationErrors)[""] +// if val.Tag != "udp_addr" { +// t.Fatalf("Index: %d udp_addr failed Error: %s", i, errs) +// } +// } +// } +// } +// } + +// func TestUDP6AddrValidation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"", false}, +// {":80", false}, +// {"127.0.0.1:80", false}, +// {"[::1]:80", true}, +// {"256.0.0.0:1", false}, +// {"[::1]", false}, +// } + +// for i, test := range tests { +// errs := validate.Field(test.param, "udp6_addr") +// if test.expected { +// if !IsEqual(errs, nil) { +// t.Fatalf("Index: %d udp6_addr failed Error: %s", i, errs) +// } +// } else { +// if IsEqual(errs, nil) { +// t.Fatalf("Index: %d udp6_addr failed Error: %s", i, errs) +// } else { +// val := errs.(ValidationErrors)[""] +// if val.Tag != "udp6_addr" { +// t.Fatalf("Index: %d udp6_addr failed Error: %s", i, errs) +// } +// } +// } +// } +// } + +// func TestUDP4AddrValidation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"", false}, +// {":80", false}, +// {"127.0.0.1:80", true}, +// {"[::1]:80", false}, // https://github.com/golang/go/issues/14037 +// {"256.0.0.0:1", false}, +// {"[::1]", false}, +// } + +// for i, test := range tests { +// errs := validate.Field(test.param, "udp4_addr") +// if test.expected { +// if !IsEqual(errs, nil) { +// t.Fatalf("Index: %d udp4_addr failed Error: %s", i, errs) +// } +// } else { +// if IsEqual(errs, nil) { +// t.Log(test.param, IsEqual(errs, nil)) +// t.Fatalf("Index: %d udp4_addr failed Error: %s", i, errs) +// } else { +// val := errs.(ValidationErrors)[""] +// if val.Tag != "udp4_addr" { +// t.Fatalf("Index: %d udp4_addr failed Error: %s", i, errs) +// } +// } +// } +// } +// } + +// func TestIPAddrValidation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"", false}, +// {"127.0.0.1", true}, +// {"127.0.0.1:80", false}, +// {"::1", true}, +// {"256.0.0.0", false}, +// {"localhost", false}, +// } + +// for i, test := range tests { +// errs := validate.Field(test.param, "ip_addr") +// if test.expected { +// if !IsEqual(errs, nil) { +// t.Fatalf("Index: %d ip_addr failed Error: %s", i, errs) +// } +// } else { +// if IsEqual(errs, nil) { +// t.Fatalf("Index: %d ip_addr failed Error: %s", i, errs) +// } else { +// val := errs.(ValidationErrors)[""] +// if val.Tag != "ip_addr" { +// t.Fatalf("Index: %d ip_addr failed Error: %s", i, errs) +// } +// } +// } +// } +// } + +// func TestIP6AddrValidation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"", false}, +// {"127.0.0.1", false}, // https://github.com/golang/go/issues/14037 +// {"127.0.0.1:80", false}, +// {"::1", true}, +// {"0:0:0:0:0:0:0:1", true}, +// {"256.0.0.0", false}, +// } + +// for i, test := range tests { +// errs := validate.Field(test.param, "ip6_addr") +// if test.expected { +// if !IsEqual(errs, nil) { +// t.Fatalf("Index: %d ip6_addr failed Error: %s", i, errs) +// } +// } else { +// if IsEqual(errs, nil) { +// t.Fatalf("Index: %d ip6_addr failed Error: %s", i, errs) +// } else { +// val := errs.(ValidationErrors)[""] +// if val.Tag != "ip6_addr" { +// t.Fatalf("Index: %d ip6_addr failed Error: %s", i, errs) +// } +// } +// } +// } +// } + +// func TestIP4AddrValidation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"", false}, +// {"127.0.0.1", true}, +// {"127.0.0.1:80", false}, +// {"::1", false}, // https://github.com/golang/go/issues/14037 +// {"256.0.0.0", false}, +// {"localhost", false}, +// } + +// for i, test := range tests { +// errs := validate.Field(test.param, "ip4_addr") +// if test.expected { +// if !IsEqual(errs, nil) { +// t.Fatalf("Index: %d ip4_addr failed Error: %s", i, errs) +// } +// } else { +// if IsEqual(errs, nil) { +// t.Log(test.param, IsEqual(errs, nil)) +// t.Fatalf("Index: %d ip4_addr failed Error: %s", i, errs) +// } else { +// val := errs.(ValidationErrors)[""] +// if val.Tag != "ip4_addr" { +// t.Fatalf("Index: %d ip4_addr failed Error: %s", i, errs) +// } +// } +// } +// } +// } + +// func TestUnixAddrValidation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"", true}, +// {"v.sock", true}, +// } + +// for i, test := range tests { +// errs := validate.Field(test.param, "unix_addr") +// if test.expected { +// if !IsEqual(errs, nil) { +// t.Fatalf("Index: %d unix_addr failed Error: %s", i, errs) +// } +// } else { +// if IsEqual(errs, nil) { +// t.Log(test.param, IsEqual(errs, nil)) +// t.Fatalf("Index: %d unix_addr failed Error: %s", i, errs) +// } else { +// val := errs.(ValidationErrors)[""] +// if val.Tag != "unix_addr" { +// t.Fatalf("Index: %d unix_addr failed Error: %s", i, errs) +// } +// } +// } +// } +// } + +// func TestSliceMapArrayChanFuncPtrInterfaceRequiredValidation(t *testing.T) { + +// var m map[string]string + +// errs := validate.Field(m, "required") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "required") + +// m = map[string]string{} +// errs = validate.Field(m, "required") +// Equal(t, errs, nil) + +// var arr [5]string +// errs = validate.Field(arr, "required") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "required") + +// arr[0] = "ok" +// errs = validate.Field(arr, "required") +// Equal(t, errs, nil) + +// var s []string +// errs = validate.Field(s, "required") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "required") + +// s = []string{} +// errs = validate.Field(s, "required") +// Equal(t, errs, nil) + +// var c chan string +// errs = validate.Field(c, "required") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "required") + +// c = make(chan string) +// errs = validate.Field(c, "required") +// Equal(t, errs, nil) + +// var tst *int +// errs = validate.Field(tst, "required") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "required") + +// one := 1 +// tst = &one +// errs = validate.Field(tst, "required") +// Equal(t, errs, nil) + +// var iface interface{} + +// errs = validate.Field(iface, "required") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "required") + +// errs = validate.Field(iface, "omitempty,required") +// Equal(t, errs, nil) + +// errs = validate.Field(iface, "") +// Equal(t, errs, nil) + +// errs = validate.FieldWithValue(nil, iface, "") +// Equal(t, errs, nil) + +// var f func(string) + +// errs = validate.Field(f, "required") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "required") + +// f = func(name string) {} + +// errs = validate.Field(f, "required") +// Equal(t, errs, nil) +// } + +// func TestDatePtrValidationIssueValidation(t *testing.T) { + +// type Test struct { +// LastViewed *time.Time +// Reminder *time.Time +// } + +// test := &Test{} + +// errs := validate.Struct(test) +// Equal(t, errs, nil) +// } + +// func TestCommaAndPipeObfuscationValidation(t *testing.T) { +// s := "My Name Is, |joeybloggs|" -func TestAliasTags(t *testing.T) { +// errs := validate.Field(s, "excludesall=0x2C") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "excludesall") - validate.RegisterAliasValidation("iscolor", "hexcolor|rgb|rgba|hsl|hsla") +// errs = validate.Field(s, "excludesall=0x7C") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "excludesall") +// } - s := "rgb(255,255,255)" - errs := validate.Field(s, "iscolor") - Equal(t, errs, nil) +// func TestBadKeyValidation(t *testing.T) { +// type Test struct { +// Name string `validate:"required, "` +// } - s = "" - errs = validate.Field(s, "omitempty,iscolor") - Equal(t, errs, nil) +// tst := &Test{ +// Name: "test", +// } - s = "rgb(255,255,0)" - errs = validate.Field(s, "iscolor,len=5") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "len") +// PanicMatches(t, func() { validate.Struct(tst) }, "Undefined validation function on field Name") - type Test struct { - Color string `validate:"iscolor"` - } +// type Test2 struct { +// Name string `validate:"required,,len=2"` +// } - tst := &Test{ - Color: "#000", - } +// tst2 := &Test2{ +// Name: "test", +// } - errs = validate.Struct(tst) - Equal(t, errs, nil) +// PanicMatches(t, func() { validate.Struct(tst2) }, "Invalid validation tag on field Name") +// } - tst.Color = "cfvre" - errs = validate.Struct(tst) - NotEqual(t, errs, nil) - AssertError(t, errs, "Test.Color", "Color", "iscolor") - Equal(t, errs.(ValidationErrors)["Test.Color"].ActualTag, "hexcolor|rgb|rgba|hsl|hsla") +// func TestInterfaceErrValidation(t *testing.T) { - validate.RegisterAliasValidation("req", "required,dive,iscolor") - arr := []string{"val1", "#fff", "#000"} +// var v1 interface{} +// var v2 interface{} - errs = validate.Field(arr, "req") - NotEqual(t, errs, nil) - AssertError(t, errs, "[0]", "[0]", "iscolor") +// v2 = 1 +// v1 = v2 - PanicMatches(t, func() { validate.RegisterAliasValidation("exists", "gt=5,lt=10") }, "Alias 'exists' either contains restricted characters or is the same as a restricted tag needed for normal operation") -} +// errs := validate.Field(v1, "len=1") +// Equal(t, errs, nil) -func TestNilValidator(t *testing.T) { +// errs = validate.Field(v2, "len=1") +// Equal(t, errs, nil) - type TestStruct struct { - Test string `validate:"required"` - } +// type ExternalCMD struct { +// Userid string `json:"userid"` +// Action uint32 `json:"action"` +// Data interface{} `json:"data,omitempty" validate:"required"` +// } - ts := TestStruct{} +// s := &ExternalCMD{ +// Userid: "123456", +// Action: 10000, +// // Data: 1, +// } - var val *Validate +// errs = validate.Struct(s) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.(ValidationErrors)), 1) +// AssertError(t, errs, "ExternalCMD.Data", "Data", "required") - fn := func(v *Validate, topStruct reflect.Value, current reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { +// type ExternalCMD2 struct { +// Userid string `json:"userid"` +// Action uint32 `json:"action"` +// Data interface{} `json:"data,omitempty" validate:"len=1"` +// } + +// s2 := &ExternalCMD2{ +// Userid: "123456", +// Action: 10000, +// // Data: 1, +// } + +// errs = validate.Struct(s2) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.(ValidationErrors)), 1) +// AssertError(t, errs, "ExternalCMD2.Data", "Data", "len") + +// s3 := &ExternalCMD2{ +// Userid: "123456", +// Action: 10000, +// Data: 2, +// } + +// errs = validate.Struct(s3) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.(ValidationErrors)), 1) +// AssertError(t, errs, "ExternalCMD2.Data", "Data", "len") + +// type Inner struct { +// Name string `validate:"required"` +// } + +// inner := &Inner{ +// Name: "", +// } + +// s4 := &ExternalCMD{ +// Userid: "123456", +// Action: 10000, +// Data: inner, +// } + +// errs = validate.Struct(s4) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.(ValidationErrors)), 1) +// AssertError(t, errs, "ExternalCMD.Data.Name", "Name", "required") + +// type TestMapStructPtr struct { +// Errs map[int]interface{} `validate:"gt=0,dive,len=2"` +// } + +// mip := map[int]interface{}{0: &Inner{"ok"}, 3: nil, 4: &Inner{"ok"}} + +// msp := &TestMapStructPtr{ +// Errs: mip, +// } + +// errs = validate.Struct(msp) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.(ValidationErrors)), 1) +// AssertError(t, errs, "TestMapStructPtr.Errs[3]", "Errs[3]", "len") + +// type TestMultiDimensionalStructs struct { +// Errs [][]interface{} `validate:"gt=0,dive,dive"` +// } + +// var errStructArray [][]interface{} + +// errStructArray = append(errStructArray, []interface{}{&Inner{"ok"}, &Inner{""}, &Inner{""}}) +// errStructArray = append(errStructArray, []interface{}{&Inner{"ok"}, &Inner{""}, &Inner{""}}) + +// tms := &TestMultiDimensionalStructs{ +// Errs: errStructArray, +// } + +// errs = validate.Struct(tms) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.(ValidationErrors)), 4) +// AssertError(t, errs, "TestMultiDimensionalStructs.Errs[0][1].Name", "Name", "required") +// AssertError(t, errs, "TestMultiDimensionalStructs.Errs[0][2].Name", "Name", "required") +// AssertError(t, errs, "TestMultiDimensionalStructs.Errs[1][1].Name", "Name", "required") +// AssertError(t, errs, "TestMultiDimensionalStructs.Errs[1][2].Name", "Name", "required") + +// type TestMultiDimensionalStructsPtr2 struct { +// Errs [][]*Inner `validate:"gt=0,dive,dive,required"` +// } + +// var errStructPtr2Array [][]*Inner + +// errStructPtr2Array = append(errStructPtr2Array, []*Inner{{"ok"}, {""}, {""}}) +// errStructPtr2Array = append(errStructPtr2Array, []*Inner{{"ok"}, {""}, {""}}) +// errStructPtr2Array = append(errStructPtr2Array, []*Inner{{"ok"}, {""}, nil}) + +// tmsp2 := &TestMultiDimensionalStructsPtr2{ +// Errs: errStructPtr2Array, +// } + +// errs = validate.Struct(tmsp2) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.(ValidationErrors)), 6) +// AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[0][1].Name", "Name", "required") +// AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[0][2].Name", "Name", "required") +// AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[1][1].Name", "Name", "required") +// AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[1][2].Name", "Name", "required") +// AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[2][1].Name", "Name", "required") +// AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[2][2]", "Errs[2][2]", "required") + +// m := map[int]interface{}{0: "ok", 3: "", 4: "ok"} + +// errs = validate.Field(m, "len=3,dive,len=2") +// NotEqual(t, errs, nil) +// Equal(t, len(errs.(ValidationErrors)), 1) +// AssertError(t, errs, "[3]", "[3]", "len") - return current.String() == field.String() - } +// errs = validate.Field(m, "len=2,dive,required") +// NotEqual(t, errs, nil) +// Equal(t, len(errs.(ValidationErrors)), 1) +// AssertError(t, errs, "", "", "len") - 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) -} +// arr := []interface{}{"ok", "", "ok"} -func TestStructPartial(t *testing.T) { +// errs = validate.Field(arr, "len=3,dive,len=2") +// NotEqual(t, errs, nil) +// Equal(t, len(errs.(ValidationErrors)), 1) +// AssertError(t, errs, "[1]", "[1]", "len") - p1 := []string{ - "NoTag", - "Required", - } +// errs = validate.Field(arr, "len=2,dive,required") +// NotEqual(t, errs, nil) +// Equal(t, len(errs.(ValidationErrors)), 1) +// AssertError(t, errs, "", "", "len") - p2 := []string{ - "SubSlice[0].Test", - "Sub", - "SubIgnore", - "Anonymous.A", - } +// type MyStruct struct { +// A, B string +// C interface{} +// } - p3 := []string{ - "SubTest.Test", - } +// var a MyStruct - p4 := []string{ - "A", - } +// a.A = "value" +// a.C = "nu" - tPartial := &TestPartial{ - NoTag: "NoTag", - Required: "Required", - - SubSlice: []*SubTest{ - { - - Test: "Required", - }, - { - - Test: "Required", - }, - }, - - Sub: &SubTest{ - Test: "1", - }, - SubIgnore: &SubTest{ - Test: "", - }, - Anonymous: struct { - A string `validate:"required"` - ASubSlice []*SubTest `validate:"required,dive"` - SubAnonStruct []struct { - Test string `validate:"required"` - OtherTest string `validate:"required"` - } `validate:"required,dive"` - }{ - A: "1", - ASubSlice: []*SubTest{ - { - Test: "Required", - }, - { - Test: "Required", - }, - }, - - SubAnonStruct: []struct { - Test string `validate:"required"` - OtherTest string `validate:"required"` - }{ - {"Required", "RequiredOther"}, - {"Required", "RequiredOther"}, - }, - }, - } +// errs = validate.Struct(a) +// Equal(t, errs, nil) +// } - // the following should all return no errors as everything is valid in - // the default state - errs := validate.StructPartial(tPartial, p1...) - Equal(t, errs, nil) +// func TestMapDiveValidation(t *testing.T) { - errs = validate.StructPartial(tPartial, p2...) - Equal(t, errs, nil) +// n := map[int]interface{}{0: nil} +// errs := validate.Field(n, "omitempty,required") +// Equal(t, errs, nil) - // this isn't really a robust test, but is ment to illustrate the ANON CASE below - errs = validate.StructPartial(tPartial.SubSlice[0], p3...) - Equal(t, errs, nil) +// m := map[int]string{0: "ok", 3: "", 4: "ok"} - errs = validate.StructExcept(tPartial, p1...) - Equal(t, errs, nil) +// errs = validate.Field(m, "len=3,dive,required") +// NotEqual(t, errs, nil) +// Equal(t, len(errs.(ValidationErrors)), 1) +// AssertError(t, errs, "[3]", "[3]", "required") - errs = validate.StructExcept(tPartial, p2...) - Equal(t, errs, nil) +// errs = validate.Field(m, "len=2,dive,required") +// NotEqual(t, errs, nil) +// Equal(t, len(errs.(ValidationErrors)), 1) +// AssertError(t, errs, "", "", "len") - // mod tParial for required feild and re-test making sure invalid fields are NOT required: - tPartial.Required = "" +// type Inner struct { +// Name string `validate:"required"` +// } - errs = validate.StructExcept(tPartial, p1...) - Equal(t, errs, nil) +// type TestMapStruct struct { +// Errs map[int]Inner `validate:"gt=0,dive"` +// } - errs = validate.StructPartial(tPartial, p2...) - Equal(t, errs, nil) +// mi := map[int]Inner{0: {"ok"}, 3: {""}, 4: {"ok"}} - // inversion and retesting Partial to generate failures: - errs = validate.StructPartial(tPartial, p1...) - NotEqual(t, errs, nil) - AssertError(t, errs, "TestPartial.Required", "Required", "required") +// ms := &TestMapStruct{ +// Errs: mi, +// } - errs = validate.StructExcept(tPartial, p2...) - AssertError(t, errs, "TestPartial.Required", "Required", "required") +// errs = validate.Struct(ms) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.(ValidationErrors)), 1) +// AssertError(t, errs, "TestMapStruct.Errs[3].Name", "Name", "required") - // reset Required field, and set nested struct - tPartial.Required = "Required" - tPartial.Anonymous.A = "" +// // for full test coverage +// s := fmt.Sprint(errs.Error()) +// NotEqual(t, s, "") - // will pass as unset feilds is not going to be tested - errs = validate.StructPartial(tPartial, p1...) - Equal(t, errs, nil) +// type TestMapTimeStruct struct { +// Errs map[int]*time.Time `validate:"gt=0,dive,required"` +// } - errs = validate.StructExcept(tPartial, p2...) - Equal(t, errs, nil) +// t1 := time.Now().UTC() - // ANON CASE the response here is strange, it clearly does what it is being told to - errs = validate.StructExcept(tPartial.Anonymous, p4...) - Equal(t, errs, nil) +// mta := map[int]*time.Time{0: &t1, 3: nil, 4: nil} - // will fail as unset feild is tested - errs = validate.StructPartial(tPartial, p2...) - NotEqual(t, errs, nil) - AssertError(t, errs, "TestPartial.Anonymous.A", "A", "required") +// mt := &TestMapTimeStruct{ +// Errs: mta, +// } - errs = validate.StructExcept(tPartial, p1...) - NotEqual(t, errs, nil) - AssertError(t, errs, "TestPartial.Anonymous.A", "A", "required") +// errs = validate.Struct(mt) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.(ValidationErrors)), 2) +// AssertError(t, errs, "TestMapTimeStruct.Errs[3]", "Errs[3]", "required") +// AssertError(t, errs, "TestMapTimeStruct.Errs[4]", "Errs[4]", "required") - // reset nested struct and unset struct in slice - tPartial.Anonymous.A = "Required" - tPartial.SubSlice[0].Test = "" +// type TestMapStructPtr struct { +// Errs map[int]*Inner `validate:"gt=0,dive,required"` +// } - // these will pass as unset item is NOT tested - errs = validate.StructPartial(tPartial, p1...) - Equal(t, errs, nil) +// mip := map[int]*Inner{0: {"ok"}, 3: nil, 4: {"ok"}} - errs = validate.StructExcept(tPartial, p2...) - Equal(t, errs, nil) +// msp := &TestMapStructPtr{ +// Errs: mip, +// } - // these will fail as unset item IS tested - errs = validate.StructExcept(tPartial, p1...) - AssertError(t, errs, "TestPartial.SubSlice[0].Test", "Test", "required") - Equal(t, len(errs.(ValidationErrors)), 1) +// errs = validate.Struct(msp) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.(ValidationErrors)), 1) +// AssertError(t, errs, "TestMapStructPtr.Errs[3]", "Errs[3]", "required") - errs = validate.StructPartial(tPartial, p2...) - NotEqual(t, errs, nil) - AssertError(t, errs, "TestPartial.SubSlice[0].Test", "Test", "required") - Equal(t, len(errs.(ValidationErrors)), 1) +// type TestMapStructPtr2 struct { +// Errs map[int]*Inner `validate:"gt=0,dive,omitempty,required"` +// } - // Unset second slice member concurrently to test dive behavior: - tPartial.SubSlice[1].Test = "" +// mip2 := map[int]*Inner{0: {"ok"}, 3: nil, 4: {"ok"}} - errs = validate.StructPartial(tPartial, p1...) - Equal(t, errs, nil) +// msp2 := &TestMapStructPtr2{ +// Errs: mip2, +// } - // NOTE: When specifying nested items, it is still the users responsibility - // to specify the dive tag, the library does not override this. - errs = validate.StructExcept(tPartial, p2...) - NotEqual(t, errs, nil) - AssertError(t, errs, "TestPartial.SubSlice[1].Test", "Test", "required") +// errs = validate.Struct(msp2) +// Equal(t, errs, nil) +// } - errs = validate.StructExcept(tPartial, p1...) - Equal(t, len(errs.(ValidationErrors)), 2) - AssertError(t, errs, "TestPartial.SubSlice[0].Test", "Test", "required") - AssertError(t, errs, "TestPartial.SubSlice[1].Test", "Test", "required") +// func TestArrayDiveValidation(t *testing.T) { - errs = validate.StructPartial(tPartial, p2...) - NotEqual(t, errs, nil) - Equal(t, len(errs.(ValidationErrors)), 1) - AssertError(t, errs, "TestPartial.SubSlice[0].Test", "Test", "required") +// arr := []string{"ok", "", "ok"} - // reset struct in slice, and unset struct in slice in unset posistion - tPartial.SubSlice[0].Test = "Required" +// errs := validate.Field(arr, "len=3,dive,required") +// NotEqual(t, errs, nil) +// Equal(t, len(errs.(ValidationErrors)), 1) +// AssertError(t, errs, "[1]", "[1]", "required") - // these will pass as the unset item is NOT tested - errs = validate.StructPartial(tPartial, p1...) - Equal(t, errs, nil) +// errs = validate.Field(arr, "len=2,dive,required") +// NotEqual(t, errs, nil) +// Equal(t, len(errs.(ValidationErrors)), 1) +// AssertError(t, errs, "", "", "len") - errs = validate.StructPartial(tPartial, p2...) - Equal(t, errs, nil) +// type BadDive struct { +// Name string `validate:"dive"` +// } - // testing for missing item by exception, yes it dives and fails - errs = validate.StructExcept(tPartial, p1...) - NotEqual(t, errs, nil) - Equal(t, len(errs.(ValidationErrors)), 1) - AssertError(t, errs, "TestPartial.SubSlice[1].Test", "Test", "required") +// bd := &BadDive{ +// Name: "TEST", +// } - errs = validate.StructExcept(tPartial, p2...) - NotEqual(t, errs, nil) - AssertError(t, errs, "TestPartial.SubSlice[1].Test", "Test", "required") +// PanicMatches(t, func() { validate.Struct(bd) }, "dive error! can't dive on a non slice or map") - tPartial.SubSlice[1].Test = "Required" +// type Test struct { +// Errs []string `validate:"gt=0,dive,required"` +// } - tPartial.Anonymous.SubAnonStruct[0].Test = "" - // these will pass as the unset item is NOT tested - errs = validate.StructPartial(tPartial, p1...) - Equal(t, errs, nil) +// test := &Test{ +// Errs: []string{"ok", "", "ok"}, +// } - errs = validate.StructPartial(tPartial, p2...) - Equal(t, errs, nil) +// errs = validate.Struct(test) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.(ValidationErrors)), 1) +// AssertError(t, errs, "Test.Errs[1]", "Errs[1]", "required") - errs = validate.StructExcept(tPartial, p1...) - NotEqual(t, errs, nil) - AssertError(t, errs, "TestPartial.Anonymous.SubAnonStruct[0].Test", "Test", "required") +// test = &Test{ +// Errs: []string{"ok", "ok", ""}, +// } + +// errs = validate.Struct(test) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.(ValidationErrors)), 1) +// AssertError(t, errs, "Test.Errs[2]", "Errs[2]", "required") + +// type TestMultiDimensional struct { +// Errs [][]string `validate:"gt=0,dive,dive,required"` +// } - errs = validate.StructExcept(tPartial, p2...) - NotEqual(t, errs, nil) - AssertError(t, errs, "TestPartial.Anonymous.SubAnonStruct[0].Test", "Test", "required") +// var errArray [][]string -} +// errArray = append(errArray, []string{"ok", "", ""}) +// errArray = append(errArray, []string{"ok", "", ""}) -func TestCrossStructLteFieldValidation(t *testing.T) { +// tm := &TestMultiDimensional{ +// Errs: errArray, +// } - type Inner struct { - CreatedAt *time.Time - String string - Int int - Uint uint - Float float64 - Array []string - } +// errs = validate.Struct(tm) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.(ValidationErrors)), 4) +// AssertError(t, errs, "TestMultiDimensional.Errs[0][1]", "Errs[0][1]", "required") +// AssertError(t, errs, "TestMultiDimensional.Errs[0][2]", "Errs[0][2]", "required") +// AssertError(t, errs, "TestMultiDimensional.Errs[1][1]", "Errs[1][1]", "required") +// AssertError(t, errs, "TestMultiDimensional.Errs[1][2]", "Errs[1][2]", "required") + +// type Inner struct { +// Name string `validate:"required"` +// } + +// type TestMultiDimensionalStructs struct { +// Errs [][]Inner `validate:"gt=0,dive,dive"` +// } + +// var errStructArray [][]Inner + +// errStructArray = append(errStructArray, []Inner{{"ok"}, {""}, {""}}) +// errStructArray = append(errStructArray, []Inner{{"ok"}, {""}, {""}}) + +// tms := &TestMultiDimensionalStructs{ +// Errs: errStructArray, +// } + +// errs = validate.Struct(tms) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.(ValidationErrors)), 4) +// AssertError(t, errs, "TestMultiDimensionalStructs.Errs[0][1].Name", "Name", "required") +// AssertError(t, errs, "TestMultiDimensionalStructs.Errs[0][2].Name", "Name", "required") +// AssertError(t, errs, "TestMultiDimensionalStructs.Errs[1][1].Name", "Name", "required") +// AssertError(t, errs, "TestMultiDimensionalStructs.Errs[1][2].Name", "Name", "required") + +// type TestMultiDimensionalStructsPtr struct { +// Errs [][]*Inner `validate:"gt=0,dive,dive"` +// } + +// var errStructPtrArray [][]*Inner + +// errStructPtrArray = append(errStructPtrArray, []*Inner{{"ok"}, {""}, {""}}) +// errStructPtrArray = append(errStructPtrArray, []*Inner{{"ok"}, {""}, {""}}) +// errStructPtrArray = append(errStructPtrArray, []*Inner{{"ok"}, {""}, nil}) + +// tmsp := &TestMultiDimensionalStructsPtr{ +// Errs: errStructPtrArray, +// } + +// errs = validate.Struct(tmsp) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.(ValidationErrors)), 5) +// AssertError(t, errs, "TestMultiDimensionalStructsPtr.Errs[0][1].Name", "Name", "required") +// AssertError(t, errs, "TestMultiDimensionalStructsPtr.Errs[0][2].Name", "Name", "required") +// AssertError(t, errs, "TestMultiDimensionalStructsPtr.Errs[1][1].Name", "Name", "required") +// AssertError(t, errs, "TestMultiDimensionalStructsPtr.Errs[1][2].Name", "Name", "required") +// AssertError(t, errs, "TestMultiDimensionalStructsPtr.Errs[2][1].Name", "Name", "required") + +// // for full test coverage +// s := fmt.Sprint(errs.Error()) +// NotEqual(t, s, "") + +// type TestMultiDimensionalStructsPtr2 struct { +// Errs [][]*Inner `validate:"gt=0,dive,dive,required"` +// } + +// var errStructPtr2Array [][]*Inner + +// errStructPtr2Array = append(errStructPtr2Array, []*Inner{{"ok"}, {""}, {""}}) +// errStructPtr2Array = append(errStructPtr2Array, []*Inner{{"ok"}, {""}, {""}}) +// errStructPtr2Array = append(errStructPtr2Array, []*Inner{{"ok"}, {""}, nil}) + +// tmsp2 := &TestMultiDimensionalStructsPtr2{ +// Errs: errStructPtr2Array, +// } + +// errs = validate.Struct(tmsp2) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.(ValidationErrors)), 6) +// AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[0][1].Name", "Name", "required") +// AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[0][2].Name", "Name", "required") +// AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[1][1].Name", "Name", "required") +// AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[1][2].Name", "Name", "required") +// AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[2][1].Name", "Name", "required") +// AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[2][2]", "Errs[2][2]", "required") + +// type TestMultiDimensionalStructsPtr3 struct { +// Errs [][]*Inner `validate:"gt=0,dive,dive,omitempty"` +// } + +// var errStructPtr3Array [][]*Inner + +// errStructPtr3Array = append(errStructPtr3Array, []*Inner{{"ok"}, {""}, {""}}) +// errStructPtr3Array = append(errStructPtr3Array, []*Inner{{"ok"}, {""}, {""}}) +// errStructPtr3Array = append(errStructPtr3Array, []*Inner{{"ok"}, {""}, nil}) + +// tmsp3 := &TestMultiDimensionalStructsPtr3{ +// Errs: errStructPtr3Array, +// } + +// errs = validate.Struct(tmsp3) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.(ValidationErrors)), 5) +// AssertError(t, errs, "TestMultiDimensionalStructsPtr3.Errs[0][1].Name", "Name", "required") +// AssertError(t, errs, "TestMultiDimensionalStructsPtr3.Errs[0][2].Name", "Name", "required") +// AssertError(t, errs, "TestMultiDimensionalStructsPtr3.Errs[1][1].Name", "Name", "required") +// AssertError(t, errs, "TestMultiDimensionalStructsPtr3.Errs[1][2].Name", "Name", "required") +// AssertError(t, errs, "TestMultiDimensionalStructsPtr3.Errs[2][1].Name", "Name", "required") + +// type TestMultiDimensionalTimeTime struct { +// Errs [][]*time.Time `validate:"gt=0,dive,dive,required"` +// } + +// var errTimePtr3Array [][]*time.Time + +// t1 := time.Now().UTC() +// t2 := time.Now().UTC() +// t3 := time.Now().UTC().Add(time.Hour * 24) + +// errTimePtr3Array = append(errTimePtr3Array, []*time.Time{&t1, &t2, &t3}) +// errTimePtr3Array = append(errTimePtr3Array, []*time.Time{&t1, &t2, nil}) +// errTimePtr3Array = append(errTimePtr3Array, []*time.Time{&t1, nil, nil}) + +// tmtp3 := &TestMultiDimensionalTimeTime{ +// Errs: errTimePtr3Array, +// } + +// errs = validate.Struct(tmtp3) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.(ValidationErrors)), 3) +// AssertError(t, errs, "TestMultiDimensionalTimeTime.Errs[1][2]", "Errs[1][2]", "required") +// AssertError(t, errs, "TestMultiDimensionalTimeTime.Errs[2][1]", "Errs[2][1]", "required") +// AssertError(t, errs, "TestMultiDimensionalTimeTime.Errs[2][2]", "Errs[2][2]", "required") + +// type TestMultiDimensionalTimeTime2 struct { +// Errs [][]*time.Time `validate:"gt=0,dive,dive,required"` +// } + +// var errTimeArray [][]*time.Time + +// t1 = time.Now().UTC() +// t2 = time.Now().UTC() +// t3 = time.Now().UTC().Add(time.Hour * 24) + +// errTimeArray = append(errTimeArray, []*time.Time{&t1, &t2, &t3}) +// errTimeArray = append(errTimeArray, []*time.Time{&t1, &t2, nil}) +// errTimeArray = append(errTimeArray, []*time.Time{&t1, nil, nil}) + +// tmtp := &TestMultiDimensionalTimeTime2{ +// Errs: errTimeArray, +// } + +// errs = validate.Struct(tmtp) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.(ValidationErrors)), 3) +// AssertError(t, errs, "TestMultiDimensionalTimeTime2.Errs[1][2]", "Errs[1][2]", "required") +// AssertError(t, errs, "TestMultiDimensionalTimeTime2.Errs[2][1]", "Errs[2][1]", "required") +// AssertError(t, errs, "TestMultiDimensionalTimeTime2.Errs[2][2]", "Errs[2][2]", "required") +// } + +// func TestNilStructPointerValidation(t *testing.T) { +// type Inner struct { +// Data string +// } + +// type Outer struct { +// Inner *Inner `validate:"omitempty"` +// } + +// inner := &Inner{ +// Data: "test", +// } + +// outer := &Outer{ +// Inner: inner, +// } + +// errs := validate.Struct(outer) +// Equal(t, errs, nil) + +// outer = &Outer{ +// Inner: nil, +// } + +// errs = validate.Struct(outer) +// Equal(t, errs, nil) + +// type Inner2 struct { +// Data string +// } + +// type Outer2 struct { +// Inner2 *Inner2 `validate:"required"` +// } + +// inner2 := &Inner2{ +// Data: "test", +// } + +// outer2 := &Outer2{ +// Inner2: inner2, +// } + +// errs = validate.Struct(outer2) +// Equal(t, errs, nil) + +// outer2 = &Outer2{ +// Inner2: nil, +// } + +// errs = validate.Struct(outer2) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "Outer2.Inner2", "Inner2", "required") + +// type Inner3 struct { +// Data string +// } + +// type Outer3 struct { +// Inner3 *Inner3 +// } + +// inner3 := &Inner3{ +// Data: "test", +// } + +// outer3 := &Outer3{ +// Inner3: inner3, +// } + +// errs = validate.Struct(outer3) +// Equal(t, errs, nil) + +// type Inner4 struct { +// Data string +// } + +// type Outer4 struct { +// Inner4 *Inner4 `validate:"-"` +// } + +// inner4 := &Inner4{ +// Data: "test", +// } + +// outer4 := &Outer4{ +// Inner4: inner4, +// } + +// errs = validate.Struct(outer4) +// Equal(t, errs, nil) +// } + +// func TestSSNValidation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"", false}, +// {"00-90-8787", false}, +// {"66690-76", false}, +// {"191 60 2869", true}, +// {"191-60-2869", true}, +// } + +// for i, test := range tests { + +// errs := validate.Field(test.param, "ssn") + +// if test.expected { +// if !IsEqual(errs, nil) { +// t.Fatalf("Index: %d SSN failed Error: %s", i, errs) +// } +// } else { +// if IsEqual(errs, nil) { +// t.Fatalf("Index: %d SSN failed Error: %s", i, errs) +// } else { +// val := errs.(ValidationErrors)[""] +// if val.Tag != "ssn" { +// t.Fatalf("Index: %d Latitude failed Error: %s", i, errs) +// } +// } +// } +// } +// } + +// func TestLongitudeValidation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"", false}, +// {"-180.000", true}, +// {"180.1", false}, +// {"+73.234", true}, +// {"+382.3811", false}, +// {"23.11111111", true}, +// } + +// for i, test := range tests { + +// errs := validate.Field(test.param, "longitude") + +// if test.expected { +// if !IsEqual(errs, nil) { +// t.Fatalf("Index: %d Longitude failed Error: %s", i, errs) +// } +// } else { +// if IsEqual(errs, nil) { +// t.Fatalf("Index: %d Longitude failed Error: %s", i, errs) +// } else { +// val := errs.(ValidationErrors)[""] +// if val.Tag != "longitude" { +// t.Fatalf("Index: %d Latitude failed Error: %s", i, errs) +// } +// } +// } +// } +// } + +// func TestLatitudeValidation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"", false}, +// {"-90.000", true}, +// {"+90", true}, +// {"47.1231231", true}, +// {"+99.9", false}, +// {"108", false}, +// } + +// for i, test := range tests { + +// errs := validate.Field(test.param, "latitude") + +// if test.expected { +// if !IsEqual(errs, nil) { +// t.Fatalf("Index: %d Latitude failed Error: %s", i, errs) +// } +// } else { +// if IsEqual(errs, nil) { +// t.Fatalf("Index: %d Latitude failed Error: %s", i, errs) +// } else { +// val := errs.(ValidationErrors)[""] +// if val.Tag != "latitude" { +// t.Fatalf("Index: %d Latitude failed Error: %s", i, errs) +// } +// } +// } +// } +// } + +// func TestDataURIValidation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"data:image/png;base64,TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4=", true}, +// {"data:text/plain;base64,Vml2YW11cyBmZXJtZW50dW0gc2VtcGVyIHBvcnRhLg==", true}, +// {"image/gif;base64,U3VzcGVuZGlzc2UgbGVjdHVzIGxlbw==", false}, +// {"data:image/gif;base64,MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuMPNS1Ufof9EW/M98FNw" + +// "UAKrwflsqVxaxQjBQnHQmiI7Vac40t8x7pIb8gLGV6wL7sBTJiPovJ0V7y7oc0Ye" + +// "rhKh0Rm4skP2z/jHwwZICgGzBvA0rH8xlhUiTvcwDCJ0kc+fh35hNt8srZQM4619" + +// "FTgB66Xmp4EtVyhpQV+t02g6NzK72oZI0vnAvqhpkxLeLiMCyrI416wHm5Tkukhx" + +// "QmcL2a6hNOyu0ixX/x2kSFXApEnVrJ+/IxGyfyw8kf4N2IZpW5nEP847lpfj0SZZ" + +// "Fwrd1mnfnDbYohX2zRptLy2ZUn06Qo9pkG5ntvFEPo9bfZeULtjYzIl6K8gJ2uGZ" + "HQIDAQAB", true}, +// {"data:image/png;base64,12345", false}, +// {"", false}, +// {"data:text,:;base85,U3VzcGVuZGlzc2UgbGVjdHVzIGxlbw==", false}, +// } + +// for i, test := range tests { + +// errs := validate.Field(test.param, "datauri") + +// if test.expected { +// if !IsEqual(errs, nil) { +// t.Fatalf("Index: %d DataURI failed Error: %s", i, errs) +// } +// } else { +// if IsEqual(errs, nil) { +// t.Fatalf("Index: %d DataURI failed Error: %s", i, errs) +// } else { +// val := errs.(ValidationErrors)[""] +// if val.Tag != "datauri" { +// t.Fatalf("Index: %d DataURI failed Error: %s", i, errs) +// } +// } +// } +// } +// } + +// func TestMultibyteValidation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"", true}, +// {"abc", false}, +// {"123", false}, +// {"<>@;.-=", false}, +// {"ひらがな・カタカナ、.漢字", true}, +// {"あいうえお foobar", true}, +// {"test@example.com", true}, +// {"test@example.com", true}, +// {"1234abcDExyz", true}, +// {"カタカナ", true}, +// } + +// for i, test := range tests { + +// errs := validate.Field(test.param, "multibyte") + +// if test.expected { +// if !IsEqual(errs, nil) { +// t.Fatalf("Index: %d Multibyte failed Error: %s", i, errs) +// } +// } else { +// if IsEqual(errs, nil) { +// t.Fatalf("Index: %d Multibyte failed Error: %s", i, errs) +// } else { +// val := errs.(ValidationErrors)[""] +// if val.Tag != "multibyte" { +// t.Fatalf("Index: %d Multibyte failed Error: %s", i, errs) +// } +// } +// } +// } +// } + +// func TestPrintableASCIIValidation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"", true}, +// {"foobar", false}, +// {"xyz098", false}, +// {"123456", false}, +// {"カタカナ", false}, +// {"foobar", true}, +// {"0987654321", true}, +// {"test@example.com", true}, +// {"1234abcDEF", true}, +// {"newline\n", false}, +// {"\x19test\x7F", false}, +// } + +// for i, test := range tests { + +// errs := validate.Field(test.param, "printascii") + +// if test.expected { +// if !IsEqual(errs, nil) { +// t.Fatalf("Index: %d Printable ASCII failed Error: %s", i, errs) +// } +// } else { +// if IsEqual(errs, nil) { +// t.Fatalf("Index: %d Printable ASCII failed Error: %s", i, errs) +// } else { +// val := errs.(ValidationErrors)[""] +// if val.Tag != "printascii" { +// t.Fatalf("Index: %d Printable ASCII failed Error: %s", i, errs) +// } +// } +// } +// } +// } + +// func TestASCIIValidation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"", true}, +// {"foobar", false}, +// {"xyz098", false}, +// {"123456", false}, +// {"カタカナ", false}, +// {"foobar", true}, +// {"0987654321", true}, +// {"test@example.com", true}, +// {"1234abcDEF", true}, +// {"", true}, +// } + +// for i, test := range tests { + +// errs := validate.Field(test.param, "ascii") + +// if test.expected { +// if !IsEqual(errs, nil) { +// t.Fatalf("Index: %d ASCII failed Error: %s", i, errs) +// } +// } else { +// if IsEqual(errs, nil) { +// t.Fatalf("Index: %d ASCII failed Error: %s", i, errs) +// } else { +// val := errs.(ValidationErrors)[""] +// if val.Tag != "ascii" { +// t.Fatalf("Index: %d ASCII failed Error: %s", i, errs) +// } +// } +// } +// } +// } + +// func TestUUID5Validation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ + +// {"", false}, +// {"xxxa987fbc9-4bed-3078-cf07-9141ba07c9f3", false}, +// {"9c858901-8a57-4791-81fe-4c455b099bc9", false}, +// {"a987fbc9-4bed-3078-cf07-9141ba07c9f3", false}, +// {"987fbc97-4bed-5078-af07-9141ba07c9f3", true}, +// {"987fbc97-4bed-5078-9f07-9141ba07c9f3", true}, +// } + +// for i, test := range tests { + +// errs := validate.Field(test.param, "uuid5") + +// if test.expected { +// if !IsEqual(errs, nil) { +// t.Fatalf("Index: %d UUID5 failed Error: %s", i, errs) +// } +// } else { +// if IsEqual(errs, nil) { +// t.Fatalf("Index: %d UUID5 failed Error: %s", i, errs) +// } else { +// val := errs.(ValidationErrors)[""] +// if val.Tag != "uuid5" { +// t.Fatalf("Index: %d UUID5 failed Error: %s", i, errs) +// } +// } +// } +// } +// } + +// func TestUUID4Validation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"", false}, +// {"xxxa987fbc9-4bed-3078-cf07-9141ba07c9f3", false}, +// {"a987fbc9-4bed-5078-af07-9141ba07c9f3", false}, +// {"934859", false}, +// {"57b73598-8764-4ad0-a76a-679bb6640eb1", true}, +// {"625e63f3-58f5-40b7-83a1-a72ad31acffb", true}, +// } + +// for i, test := range tests { + +// errs := validate.Field(test.param, "uuid4") + +// if test.expected { +// if !IsEqual(errs, nil) { +// t.Fatalf("Index: %d UUID4 failed Error: %s", i, errs) +// } +// } else { +// if IsEqual(errs, nil) { +// t.Fatalf("Index: %d UUID4 failed Error: %s", i, errs) +// } else { +// val := errs.(ValidationErrors)[""] +// if val.Tag != "uuid4" { +// t.Fatalf("Index: %d UUID4 failed Error: %s", i, errs) +// } +// } +// } +// } +// } + +// func TestUUID3Validation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"", false}, +// {"412452646", false}, +// {"xxxa987fbc9-4bed-3078-cf07-9141ba07c9f3", false}, +// {"a987fbc9-4bed-4078-8f07-9141ba07c9f3", false}, +// {"a987fbc9-4bed-3078-cf07-9141ba07c9f3", true}, +// } + +// for i, test := range tests { + +// errs := validate.Field(test.param, "uuid3") + +// if test.expected { +// if !IsEqual(errs, nil) { +// t.Fatalf("Index: %d UUID3 failed Error: %s", i, errs) +// } +// } else { +// if IsEqual(errs, nil) { +// t.Fatalf("Index: %d UUID3 failed Error: %s", i, errs) +// } else { +// val := errs.(ValidationErrors)[""] +// if val.Tag != "uuid3" { +// t.Fatalf("Index: %d UUID3 failed Error: %s", i, errs) +// } +// } +// } +// } +// } + +// func TestUUIDValidation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"", false}, +// {"xxxa987fbc9-4bed-3078-cf07-9141ba07c9f3", false}, +// {"a987fbc9-4bed-3078-cf07-9141ba07c9f3xxx", false}, +// {"a987fbc94bed3078cf079141ba07c9f3", false}, +// {"934859", false}, +// {"987fbc9-4bed-3078-cf07a-9141ba07c9f3", false}, +// {"aaaaaaaa-1111-1111-aaag-111111111111", false}, +// {"a987fbc9-4bed-3078-cf07-9141ba07c9f3", true}, +// } + +// for i, test := range tests { + +// errs := validate.Field(test.param, "uuid") + +// if test.expected { +// if !IsEqual(errs, nil) { +// t.Fatalf("Index: %d UUID failed Error: %s", i, errs) +// } +// } else { +// if IsEqual(errs, nil) { +// t.Fatalf("Index: %d UUID failed Error: %s", i, errs) +// } else { +// val := errs.(ValidationErrors)[""] +// if val.Tag != "uuid" { +// t.Fatalf("Index: %d UUID failed Error: %s", i, errs) +// } +// } +// } +// } +// } + +// func TestISBNValidation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"", false}, +// {"foo", false}, +// {"3836221195", true}, +// {"1-61729-085-8", true}, +// {"3 423 21412 0", true}, +// {"3 401 01319 X", true}, +// {"9784873113685", true}, +// {"978-4-87311-368-5", true}, +// {"978 3401013190", true}, +// {"978-3-8362-2119-1", true}, +// } + +// for i, test := range tests { + +// errs := validate.Field(test.param, "isbn") + +// if test.expected { +// if !IsEqual(errs, nil) { +// t.Fatalf("Index: %d ISBN failed Error: %s", i, errs) +// } +// } else { +// if IsEqual(errs, nil) { +// t.Fatalf("Index: %d ISBN failed Error: %s", i, errs) +// } else { +// val := errs.(ValidationErrors)[""] +// if val.Tag != "isbn" { +// t.Fatalf("Index: %d ISBN failed Error: %s", i, errs) +// } +// } +// } +// } +// } + +// func TestISBN13Validation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"", false}, +// {"foo", false}, +// {"3-8362-2119-5", false}, +// {"01234567890ab", false}, +// {"978 3 8362 2119 0", false}, +// {"9784873113685", true}, +// {"978-4-87311-368-5", true}, +// {"978 3401013190", true}, +// {"978-3-8362-2119-1", true}, +// } + +// for i, test := range tests { + +// errs := validate.Field(test.param, "isbn13") + +// if test.expected { +// if !IsEqual(errs, nil) { +// t.Fatalf("Index: %d ISBN13 failed Error: %s", i, errs) +// } +// } else { +// if IsEqual(errs, nil) { +// t.Fatalf("Index: %d ISBN13 failed Error: %s", i, errs) +// } else { +// val := errs.(ValidationErrors)[""] +// if val.Tag != "isbn13" { +// t.Fatalf("Index: %d ISBN13 failed Error: %s", i, errs) +// } +// } +// } +// } +// } + +// func TestISBN10Validation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"", false}, +// {"foo", false}, +// {"3423214121", false}, +// {"978-3836221191", false}, +// {"3-423-21412-1", false}, +// {"3 423 21412 1", false}, +// {"3836221195", true}, +// {"1-61729-085-8", true}, +// {"3 423 21412 0", true}, +// {"3 401 01319 X", true}, +// } + +// for i, test := range tests { + +// errs := validate.Field(test.param, "isbn10") + +// if test.expected { +// if !IsEqual(errs, nil) { +// t.Fatalf("Index: %d ISBN10 failed Error: %s", i, errs) +// } +// } else { +// if IsEqual(errs, nil) { +// t.Fatalf("Index: %d ISBN10 failed Error: %s", i, errs) +// } else { +// val := errs.(ValidationErrors)[""] +// if val.Tag != "isbn10" { +// t.Fatalf("Index: %d ISBN10 failed Error: %s", i, errs) +// } +// } +// } +// } +// } + +// func TestExcludesRuneValidation(t *testing.T) { + +// tests := []struct { +// Value string `validate:"excludesrune=☻"` +// Tag string +// ExpectedNil bool +// }{ +// {Value: "a☺b☻c☹d", Tag: "excludesrune=☻", ExpectedNil: false}, +// {Value: "abcd", Tag: "excludesrune=☻", ExpectedNil: true}, +// } + +// for i, s := range tests { +// errs := validate.Field(s.Value, s.Tag) + +// if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { +// t.Fatalf("Index: %d failed Error: %s", i, errs) +// } + +// errs = validate.Struct(s) + +// if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { +// t.Fatalf("Index: %d failed Error: %s", i, errs) +// } +// } +// } + +// func TestExcludesAllValidation(t *testing.T) { + +// tests := []struct { +// Value string `validate:"excludesall=@!{}[]"` +// Tag string +// ExpectedNil bool +// }{ +// {Value: "abcd@!jfk", Tag: "excludesall=@!{}[]", ExpectedNil: false}, +// {Value: "abcdefg", Tag: "excludesall=@!{}[]", ExpectedNil: true}, +// } + +// for i, s := range tests { +// errs := validate.Field(s.Value, s.Tag) + +// if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { +// t.Fatalf("Index: %d failed Error: %s", i, errs) +// } + +// errs = validate.Struct(s) + +// if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { +// t.Fatalf("Index: %d failed Error: %s", i, errs) +// } +// } + +// username := "joeybloggs " + +// errs := validate.Field(username, "excludesall=@ ") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "excludesall") + +// excluded := "," + +// errs = validate.Field(excluded, "excludesall=!@#$%^&*()_+.0x2C?") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "excludesall") + +// excluded = "=" + +// errs = validate.Field(excluded, "excludesall=!@#$%^&*()_+.0x2C=?") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "excludesall") +// } + +// func TestExcludesValidation(t *testing.T) { + +// tests := []struct { +// Value string `validate:"excludes=@"` +// Tag string +// ExpectedNil bool +// }{ +// {Value: "abcd@!jfk", Tag: "excludes=@", ExpectedNil: false}, +// {Value: "abcdq!jfk", Tag: "excludes=@", ExpectedNil: true}, +// } + +// for i, s := range tests { +// errs := validate.Field(s.Value, s.Tag) + +// if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { +// t.Fatalf("Index: %d failed Error: %s", i, errs) +// } + +// errs = validate.Struct(s) + +// if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { +// t.Fatalf("Index: %d failed Error: %s", i, errs) +// } +// } +// } + +// func TestContainsRuneValidation(t *testing.T) { + +// tests := []struct { +// Value string `validate:"containsrune=☻"` +// Tag string +// ExpectedNil bool +// }{ +// {Value: "a☺b☻c☹d", Tag: "containsrune=☻", ExpectedNil: true}, +// {Value: "abcd", Tag: "containsrune=☻", ExpectedNil: false}, +// } + +// for i, s := range tests { +// errs := validate.Field(s.Value, s.Tag) + +// if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { +// t.Fatalf("Index: %d failed Error: %s", i, errs) +// } + +// errs = validate.Struct(s) + +// if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { +// t.Fatalf("Index: %d failed Error: %s", i, errs) +// } +// } +// } + +// func TestContainsAnyValidation(t *testing.T) { + +// tests := []struct { +// Value string `validate:"containsany=@!{}[]"` +// Tag string +// ExpectedNil bool +// }{ +// {Value: "abcd@!jfk", Tag: "containsany=@!{}[]", ExpectedNil: true}, +// {Value: "abcdefg", Tag: "containsany=@!{}[]", ExpectedNil: false}, +// } + +// for i, s := range tests { +// errs := validate.Field(s.Value, s.Tag) + +// if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { +// t.Fatalf("Index: %d failed Error: %s", i, errs) +// } + +// errs = validate.Struct(s) + +// if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { +// t.Fatalf("Index: %d failed Error: %s", i, errs) +// } +// } +// } + +// func TestContainsValidation(t *testing.T) { + +// tests := []struct { +// Value string `validate:"contains=@"` +// Tag string +// ExpectedNil bool +// }{ +// {Value: "abcd@!jfk", Tag: "contains=@", ExpectedNil: true}, +// {Value: "abcdq!jfk", Tag: "contains=@", ExpectedNil: false}, +// } + +// for i, s := range tests { +// errs := validate.Field(s.Value, s.Tag) + +// if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { +// t.Fatalf("Index: %d failed Error: %s", i, errs) +// } + +// errs = validate.Struct(s) + +// if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { +// t.Fatalf("Index: %d failed Error: %s", i, errs) +// } +// } +// } + +// func TestIsNeFieldValidation(t *testing.T) { + +// var j uint64 +// var k float64 +// s := "abcd" +// i := 1 +// j = 1 +// k = 1.543 +// arr := []string{"test"} +// now := time.Now().UTC() + +// var j2 uint64 +// var k2 float64 +// s2 := "abcdef" +// i2 := 3 +// j2 = 2 +// k2 = 1.5434456 +// arr2 := []string{"test", "test2"} +// arr3 := []string{"test"} +// now2 := now + +// errs := validate.FieldWithValue(s, s2, "nefield") +// Equal(t, errs, nil) + +// errs = validate.FieldWithValue(i2, i, "nefield") +// Equal(t, errs, nil) + +// errs = validate.FieldWithValue(j2, j, "nefield") +// Equal(t, errs, nil) + +// errs = validate.FieldWithValue(k2, k, "nefield") +// Equal(t, errs, nil) + +// errs = validate.FieldWithValue(arr2, arr, "nefield") +// Equal(t, errs, nil) + +// errs = validate.FieldWithValue(now2, now, "nefield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "nefield") + +// errs = validate.FieldWithValue(arr3, arr, "nefield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "nefield") + +// type Test struct { +// Start *time.Time `validate:"nefield=End"` +// End *time.Time +// } + +// sv := &Test{ +// Start: &now, +// End: &now, +// } + +// errs = validate.Struct(sv) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "Test.Start", "Start", "nefield") + +// now3 := time.Now().UTC() + +// sv = &Test{ +// Start: &now, +// End: &now3, +// } + +// errs = validate.Struct(sv) +// Equal(t, errs, nil) + +// errs = validate.FieldWithValue(nil, 1, "nefield") +// Equal(t, errs, nil) + +// errs = validate.FieldWithValue(sv, now, "nefield") +// Equal(t, errs, nil) + +// type Test2 struct { +// Start *time.Time `validate:"nefield=NonExistantField"` +// End *time.Time +// } + +// sv2 := &Test2{ +// Start: &now, +// End: &now, +// } - type Test struct { - Inner *Inner - CreatedAt *time.Time `validate:"ltecsfield=Inner.CreatedAt"` - String string `validate:"ltecsfield=Inner.String"` - Int int `validate:"ltecsfield=Inner.Int"` - Uint uint `validate:"ltecsfield=Inner.Uint"` - Float float64 `validate:"ltecsfield=Inner.Float"` - Array []string `validate:"ltecsfield=Inner.Array"` - } +// errs = validate.Struct(sv2) +// Equal(t, errs, nil) +// } - now := time.Now().UTC() - then := now.Add(time.Hour * 5) +// func TestIsNeValidation(t *testing.T) { + +// var j uint64 +// var k float64 +// s := "abcdef" +// i := 3 +// j = 2 +// k = 1.5434 +// arr := []string{"test"} +// now := time.Now().UTC() + +// errs := validate.Field(s, "ne=abcd") +// Equal(t, errs, nil) + +// errs = validate.Field(i, "ne=1") +// Equal(t, errs, nil) + +// errs = validate.Field(j, "ne=1") +// Equal(t, errs, nil) + +// errs = validate.Field(k, "ne=1.543") +// Equal(t, errs, nil) - inner := &Inner{ - CreatedAt: &then, - String: "abcd", - Int: 13, - Uint: 13, - Float: 1.13, - Array: []string{"val1", "val2"}, - } +// errs = validate.Field(arr, "ne=2") +// Equal(t, errs, nil) + +// errs = validate.Field(arr, "ne=1") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "ne") - test := &Test{ - Inner: inner, - CreatedAt: &now, - String: "abc", - Int: 12, - Uint: 12, - Float: 1.12, - Array: []string{"val1"}, - } +// PanicMatches(t, func() { validate.Field(now, "ne=now") }, "Bad field type time.Time") +// } - errs := validate.Struct(test) - Equal(t, errs, nil) +// func TestIsEqFieldValidation(t *testing.T) { - test.CreatedAt = &then - test.String = "abcd" - test.Int = 13 - test.Uint = 13 - test.Float = 1.13 - test.Array = []string{"val1", "val2"} +// var j uint64 +// var k float64 +// s := "abcd" +// i := 1 +// j = 1 +// k = 1.543 +// arr := []string{"test"} +// now := time.Now().UTC() + +// var j2 uint64 +// var k2 float64 +// s2 := "abcd" +// i2 := 1 +// j2 = 1 +// k2 = 1.543 +// arr2 := []string{"test"} +// arr3 := []string{"test", "test2"} +// now2 := now + +// errs := validate.FieldWithValue(s, s2, "eqfield") +// Equal(t, errs, nil) + +// errs = validate.FieldWithValue(i2, i, "eqfield") +// Equal(t, errs, nil) + +// errs = validate.FieldWithValue(j2, j, "eqfield") +// Equal(t, errs, nil) + +// errs = validate.FieldWithValue(k2, k, "eqfield") +// Equal(t, errs, nil) + +// errs = validate.FieldWithValue(arr2, arr, "eqfield") +// Equal(t, errs, nil) + +// errs = validate.FieldWithValue(now2, now, "eqfield") +// Equal(t, errs, nil) + +// errs = validate.FieldWithValue(arr3, arr, "eqfield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "eqfield") - errs = validate.Struct(test) - Equal(t, errs, nil) +// type Test struct { +// Start *time.Time `validate:"eqfield=End"` +// End *time.Time +// } + +// sv := &Test{ +// Start: &now, +// End: &now, +// } - after := now.Add(time.Hour * 10) +// errs = validate.Struct(sv) +// Equal(t, errs, nil) - test.CreatedAt = &after - test.String = "abce" - test.Int = 14 - test.Uint = 14 - test.Float = 1.14 - test.Array = []string{"val1", "val2", "val3"} +// now3 := time.Now().UTC() - errs = validate.Struct(test) - NotEqual(t, errs, nil) - AssertError(t, errs, "Test.CreatedAt", "CreatedAt", "ltecsfield") - AssertError(t, errs, "Test.String", "String", "ltecsfield") - AssertError(t, errs, "Test.Int", "Int", "ltecsfield") - AssertError(t, errs, "Test.Uint", "Uint", "ltecsfield") - AssertError(t, errs, "Test.Float", "Float", "ltecsfield") - AssertError(t, errs, "Test.Array", "Array", "ltecsfield") - - errs = validate.FieldWithValue(1, "", "ltecsfield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "ltecsfield") +// sv = &Test{ +// Start: &now, +// End: &now3, +// } - errs = validate.FieldWithValue(test, now, "ltecsfield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "ltecsfield") -} +// errs = validate.Struct(sv) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "Test.Start", "Start", "eqfield") -func TestCrossStructLtFieldValidation(t *testing.T) { +// errs = validate.FieldWithValue(nil, 1, "eqfield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "eqfield") + +// channel := make(chan string) +// errs = validate.FieldWithValue(5, channel, "eqfield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "eqfield") - type Inner struct { - CreatedAt *time.Time - String string - Int int - Uint uint - Float float64 - Array []string - } +// errs = validate.FieldWithValue(5, now, "eqfield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "eqfield") - type Test struct { - Inner *Inner - CreatedAt *time.Time `validate:"ltcsfield=Inner.CreatedAt"` - String string `validate:"ltcsfield=Inner.String"` - Int int `validate:"ltcsfield=Inner.Int"` - Uint uint `validate:"ltcsfield=Inner.Uint"` - Float float64 `validate:"ltcsfield=Inner.Float"` - Array []string `validate:"ltcsfield=Inner.Array"` - } +// type Test2 struct { +// Start *time.Time `validate:"eqfield=NonExistantField"` +// End *time.Time +// } - now := time.Now().UTC() - then := now.Add(time.Hour * 5) +// sv2 := &Test2{ +// Start: &now, +// End: &now, +// } - inner := &Inner{ - CreatedAt: &then, - String: "abcd", - Int: 13, - Uint: 13, - Float: 1.13, - Array: []string{"val1", "val2"}, - } +// errs = validate.Struct(sv2) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "Test2.Start", "Start", "eqfield") - test := &Test{ - Inner: inner, - CreatedAt: &now, - String: "abc", - Int: 12, - Uint: 12, - Float: 1.12, - Array: []string{"val1"}, - } +// type Inner struct { +// Name string +// } - errs := validate.Struct(test) - Equal(t, errs, nil) +// type TStruct struct { +// Inner *Inner +// CreatedAt *time.Time `validate:"eqfield=Inner"` +// } + +// inner := &Inner{ +// Name: "NAME", +// } - test.CreatedAt = &then - test.String = "abcd" - test.Int = 13 - test.Uint = 13 - test.Float = 1.13 - test.Array = []string{"val1", "val2"} +// test := &TStruct{ +// Inner: inner, +// CreatedAt: &now, +// } - errs = validate.Struct(test) - NotEqual(t, errs, nil) - AssertError(t, errs, "Test.CreatedAt", "CreatedAt", "ltcsfield") - AssertError(t, errs, "Test.String", "String", "ltcsfield") - AssertError(t, errs, "Test.Int", "Int", "ltcsfield") - AssertError(t, errs, "Test.Uint", "Uint", "ltcsfield") - AssertError(t, errs, "Test.Float", "Float", "ltcsfield") - AssertError(t, errs, "Test.Array", "Array", "ltcsfield") - - errs = validate.FieldWithValue(1, "", "ltcsfield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "ltcsfield") +// errs = validate.Struct(test) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "TStruct.CreatedAt", "CreatedAt", "eqfield") +// } - errs = validate.FieldWithValue(test, now, "ltcsfield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "ltcsfield") -} +// func TestIsEqValidation(t *testing.T) { -func TestCrossStructGteFieldValidation(t *testing.T) { +// var j uint64 +// var k float64 +// s := "abcd" +// i := 1 +// j = 1 +// k = 1.543 +// arr := []string{"test"} +// now := time.Now().UTC() - type Inner struct { - CreatedAt *time.Time - String string - Int int - Uint uint - Float float64 - Array []string - } +// errs := validate.Field(s, "eq=abcd") +// Equal(t, errs, nil) - type Test struct { - Inner *Inner - CreatedAt *time.Time `validate:"gtecsfield=Inner.CreatedAt"` - String string `validate:"gtecsfield=Inner.String"` - Int int `validate:"gtecsfield=Inner.Int"` - Uint uint `validate:"gtecsfield=Inner.Uint"` - Float float64 `validate:"gtecsfield=Inner.Float"` - Array []string `validate:"gtecsfield=Inner.Array"` - } +// errs = validate.Field(i, "eq=1") +// Equal(t, errs, nil) - now := time.Now().UTC() - then := now.Add(time.Hour * -5) +// errs = validate.Field(j, "eq=1") +// Equal(t, errs, nil) - inner := &Inner{ - CreatedAt: &then, - String: "abcd", - Int: 13, - Uint: 13, - Float: 1.13, - Array: []string{"val1", "val2"}, - } +// errs = validate.Field(k, "eq=1.543") +// Equal(t, errs, nil) - test := &Test{ - Inner: inner, - CreatedAt: &now, - String: "abcde", - Int: 14, - Uint: 14, - Float: 1.14, - Array: []string{"val1", "val2", "val3"}, - } +// errs = validate.Field(arr, "eq=1") +// Equal(t, errs, nil) - errs := validate.Struct(test) - Equal(t, errs, nil) +// errs = validate.Field(arr, "eq=2") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "eq") - test.CreatedAt = &then - test.String = "abcd" - test.Int = 13 - test.Uint = 13 - test.Float = 1.13 - test.Array = []string{"val1", "val2"} +// PanicMatches(t, func() { validate.Field(now, "eq=now") }, "Bad field type time.Time") +// } - errs = validate.Struct(test) - Equal(t, errs, nil) +// func TestBase64Validation(t *testing.T) { - before := now.Add(time.Hour * -10) +// s := "dW5pY29ybg==" - test.CreatedAt = &before - test.String = "abc" - test.Int = 12 - test.Uint = 12 - test.Float = 1.12 - test.Array = []string{"val1"} +// errs := validate.Field(s, "base64") +// Equal(t, errs, nil) - errs = validate.Struct(test) - NotEqual(t, errs, nil) - AssertError(t, errs, "Test.CreatedAt", "CreatedAt", "gtecsfield") - AssertError(t, errs, "Test.String", "String", "gtecsfield") - AssertError(t, errs, "Test.Int", "Int", "gtecsfield") - AssertError(t, errs, "Test.Uint", "Uint", "gtecsfield") - AssertError(t, errs, "Test.Float", "Float", "gtecsfield") - AssertError(t, errs, "Test.Array", "Array", "gtecsfield") - - errs = validate.FieldWithValue(1, "", "gtecsfield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "gtecsfield") +// s = "dGhpIGlzIGEgdGVzdCBiYXNlNjQ=" +// errs = validate.Field(s, "base64") +// Equal(t, errs, nil) - errs = validate.FieldWithValue(test, now, "gtecsfield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "gtecsfield") -} +// s = "" +// errs = validate.Field(s, "base64") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "base64") -func TestCrossStructGtFieldValidation(t *testing.T) { +// s = "dW5pY29ybg== foo bar" +// errs = validate.Field(s, "base64") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "base64") +// } - type Inner struct { - CreatedAt *time.Time - String string - Int int - Uint uint - Float float64 - Array []string - } +// func TestNoStructLevelValidation(t *testing.T) { - type Test struct { - Inner *Inner - CreatedAt *time.Time `validate:"gtcsfield=Inner.CreatedAt"` - String string `validate:"gtcsfield=Inner.String"` - Int int `validate:"gtcsfield=Inner.Int"` - Uint uint `validate:"gtcsfield=Inner.Uint"` - Float float64 `validate:"gtcsfield=Inner.Float"` - Array []string `validate:"gtcsfield=Inner.Array"` - } +// type Inner struct { +// Test string `validate:"len=5"` +// } - now := time.Now().UTC() - then := now.Add(time.Hour * -5) +// type Outer struct { +// InnerStruct *Inner `validate:"required,nostructlevel"` +// } - inner := &Inner{ - CreatedAt: &then, - String: "abcd", - Int: 13, - Uint: 13, - Float: 1.13, - Array: []string{"val1", "val2"}, - } +// outer := &Outer{ +// InnerStruct: nil, +// } - test := &Test{ - Inner: inner, - CreatedAt: &now, - String: "abcde", - Int: 14, - Uint: 14, - Float: 1.14, - Array: []string{"val1", "val2", "val3"}, - } +// errs := validate.Struct(outer) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "Outer.InnerStruct", "InnerStruct", "required") - errs := validate.Struct(test) - Equal(t, errs, nil) +// inner := &Inner{ +// Test: "1234", +// } - test.CreatedAt = &then - test.String = "abcd" - test.Int = 13 - test.Uint = 13 - test.Float = 1.13 - test.Array = []string{"val1", "val2"} +// outer = &Outer{ +// InnerStruct: inner, +// } - errs = validate.Struct(test) - NotEqual(t, errs, nil) - AssertError(t, errs, "Test.CreatedAt", "CreatedAt", "gtcsfield") - AssertError(t, errs, "Test.String", "String", "gtcsfield") - AssertError(t, errs, "Test.Int", "Int", "gtcsfield") - AssertError(t, errs, "Test.Uint", "Uint", "gtcsfield") - AssertError(t, errs, "Test.Float", "Float", "gtcsfield") - AssertError(t, errs, "Test.Array", "Array", "gtcsfield") - - errs = validate.FieldWithValue(1, "", "gtcsfield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "gtcsfield") +// errs = validate.Struct(outer) +// Equal(t, errs, nil) +// } - errs = validate.FieldWithValue(test, now, "gtcsfield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "gtcsfield") -} +// func TestStructOnlyValidation(t *testing.T) { -func TestCrossStructNeFieldValidation(t *testing.T) { +// type Inner struct { +// Test string `validate:"len=5"` +// } - type Inner struct { - CreatedAt *time.Time - } +// type Outer struct { +// InnerStruct *Inner `validate:"required,structonly"` +// } - type Test struct { - Inner *Inner - CreatedAt *time.Time `validate:"necsfield=Inner.CreatedAt"` - } +// outer := &Outer{ +// InnerStruct: nil, +// } - now := time.Now().UTC() - then := now.Add(time.Hour * 5) +// errs := validate.Struct(outer) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "Outer.InnerStruct", "InnerStruct", "required") - inner := &Inner{ - CreatedAt: &then, - } +// inner := &Inner{ +// Test: "1234", +// } - test := &Test{ - Inner: inner, - CreatedAt: &now, - } +// outer = &Outer{ +// InnerStruct: inner, +// } - errs := validate.Struct(test) - Equal(t, errs, nil) +// errs = validate.Struct(outer) +// Equal(t, errs, nil) +// } - test.CreatedAt = &then +// func TestGtField(t *testing.T) { - errs = validate.Struct(test) - NotEqual(t, errs, nil) - AssertError(t, errs, "Test.CreatedAt", "CreatedAt", "necsfield") - - var j uint64 - var k float64 - var j2 uint64 - var k2 float64 - s := "abcd" - i := 1 - j = 1 - k = 1.543 - arr := []string{"test"} - - s2 := "abcd" - i2 := 1 - j2 = 1 - k2 = 1.543 - arr2 := []string{"test"} - arr3 := []string{"test", "test2"} - now2 := now - - errs = validate.FieldWithValue(s, s2, "necsfield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "necsfield") +// type TimeTest struct { +// Start *time.Time `validate:"required,gt"` +// End *time.Time `validate:"required,gt,gtfield=Start"` +// } - errs = validate.FieldWithValue(i2, i, "necsfield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "necsfield") +// now := time.Now() +// start := now.Add(time.Hour * 24) +// end := start.Add(time.Hour * 24) - errs = validate.FieldWithValue(j2, j, "necsfield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "necsfield") +// timeTest := &TimeTest{ +// Start: &start, +// End: &end, +// } - errs = validate.FieldWithValue(k2, k, "necsfield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "necsfield") +// errs := validate.Struct(timeTest) +// Equal(t, errs, nil) - errs = validate.FieldWithValue(arr2, arr, "necsfield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "necsfield") +// timeTest = &TimeTest{ +// Start: &end, +// End: &start, +// } - errs = validate.FieldWithValue(now2, now, "necsfield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "necsfield") +// errs = validate.Struct(timeTest) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "TimeTest.End", "End", "gtfield") - errs = validate.FieldWithValue(arr3, arr, "necsfield") - Equal(t, errs, nil) +// errs = validate.FieldWithValue(&start, &end, "gtfield") +// Equal(t, errs, nil) - type SInner struct { - Name string - } +// errs = validate.FieldWithValue(&end, &start, "gtfield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "gtfield") - type TStruct struct { - Inner *SInner - CreatedAt *time.Time `validate:"necsfield=Inner"` - } +// errs = validate.FieldWithValue(&timeTest, &end, "gtfield") +// NotEqual(t, errs, nil) - sinner := &SInner{ - Name: "NAME", - } +// errs = validate.FieldWithValue("test", "test bigger", "gtfield") +// Equal(t, errs, nil) - test2 := &TStruct{ - Inner: sinner, - CreatedAt: &now, - } +// type IntTest struct { +// Val1 int `validate:"required"` +// Val2 int `validate:"required,gtfield=Val1"` +// } - errs = validate.Struct(test2) - Equal(t, errs, nil) +// intTest := &IntTest{ +// Val1: 1, +// Val2: 5, +// } - test2.Inner = nil - errs = validate.Struct(test2) - Equal(t, errs, nil) +// errs = validate.Struct(intTest) +// Equal(t, errs, nil) - errs = validate.FieldWithValue(nil, 1, "necsfield") - Equal(t, errs, nil) -} +// intTest = &IntTest{ +// Val1: 5, +// Val2: 1, +// } -func TestCrossStructEqFieldValidation(t *testing.T) { +// errs = validate.Struct(intTest) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "IntTest.Val2", "Val2", "gtfield") - type Inner struct { - CreatedAt *time.Time - } +// errs = validate.FieldWithValue(int(1), int(5), "gtfield") +// Equal(t, errs, nil) - type Test struct { - Inner *Inner - CreatedAt *time.Time `validate:"eqcsfield=Inner.CreatedAt"` - } +// errs = validate.FieldWithValue(int(5), int(1), "gtfield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "gtfield") - now := time.Now().UTC() +// type UIntTest struct { +// Val1 uint `validate:"required"` +// Val2 uint `validate:"required,gtfield=Val1"` +// } - inner := &Inner{ - CreatedAt: &now, - } +// uIntTest := &UIntTest{ +// Val1: 1, +// Val2: 5, +// } - test := &Test{ - Inner: inner, - CreatedAt: &now, - } +// errs = validate.Struct(uIntTest) +// Equal(t, errs, nil) - errs := validate.Struct(test) - Equal(t, errs, nil) +// uIntTest = &UIntTest{ +// Val1: 5, +// Val2: 1, +// } - newTime := time.Now().UTC() - test.CreatedAt = &newTime +// errs = validate.Struct(uIntTest) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "UIntTest.Val2", "Val2", "gtfield") - errs = validate.Struct(test) - NotEqual(t, errs, nil) - AssertError(t, errs, "Test.CreatedAt", "CreatedAt", "eqcsfield") - - var j uint64 - var k float64 - s := "abcd" - i := 1 - j = 1 - k = 1.543 - arr := []string{"test"} - - var j2 uint64 - var k2 float64 - s2 := "abcd" - i2 := 1 - j2 = 1 - k2 = 1.543 - arr2 := []string{"test"} - arr3 := []string{"test", "test2"} - now2 := now - - errs = validate.FieldWithValue(s, s2, "eqcsfield") - Equal(t, errs, nil) +// errs = validate.FieldWithValue(uint(1), uint(5), "gtfield") +// Equal(t, errs, nil) - errs = validate.FieldWithValue(i2, i, "eqcsfield") - Equal(t, errs, nil) +// errs = validate.FieldWithValue(uint(5), uint(1), "gtfield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "gtfield") - errs = validate.FieldWithValue(j2, j, "eqcsfield") - Equal(t, errs, nil) +// type FloatTest struct { +// Val1 float64 `validate:"required"` +// Val2 float64 `validate:"required,gtfield=Val1"` +// } + +// floatTest := &FloatTest{ +// Val1: 1, +// Val2: 5, +// } + +// errs = validate.Struct(floatTest) +// Equal(t, errs, nil) + +// floatTest = &FloatTest{ +// Val1: 5, +// Val2: 1, +// } + +// errs = validate.Struct(floatTest) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "FloatTest.Val2", "Val2", "gtfield") + +// errs = validate.FieldWithValue(float32(1), float32(5), "gtfield") +// Equal(t, errs, nil) - errs = validate.FieldWithValue(k2, k, "eqcsfield") - Equal(t, errs, nil) +// errs = validate.FieldWithValue(float32(5), float32(1), "gtfield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "gtfield") - errs = validate.FieldWithValue(arr2, arr, "eqcsfield") - Equal(t, errs, nil) +// errs = validate.FieldWithValue(nil, 1, "gtfield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "gtfield") + +// errs = validate.FieldWithValue(5, "T", "gtfield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "gtfield") + +// errs = validate.FieldWithValue(5, start, "gtfield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "gtfield") + +// type TimeTest2 struct { +// Start *time.Time `validate:"required"` +// End *time.Time `validate:"required,gtfield=NonExistantField"` +// } + +// timeTest2 := &TimeTest2{ +// Start: &start, +// End: &end, +// } + +// errs = validate.Struct(timeTest2) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "TimeTest2.End", "End", "gtfield") +// } + +// func TestLtField(t *testing.T) { + +// type TimeTest struct { +// Start *time.Time `validate:"required,lt,ltfield=End"` +// End *time.Time `validate:"required,lt"` +// } + +// now := time.Now() +// start := now.Add(time.Hour * 24 * -1 * 2) +// end := start.Add(time.Hour * 24) + +// timeTest := &TimeTest{ +// Start: &start, +// End: &end, +// } + +// errs := validate.Struct(timeTest) +// Equal(t, errs, nil) + +// timeTest = &TimeTest{ +// Start: &end, +// End: &start, +// } + +// errs = validate.Struct(timeTest) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "TimeTest.Start", "Start", "ltfield") + +// errs = validate.FieldWithValue(&end, &start, "ltfield") +// Equal(t, errs, nil) + +// errs = validate.FieldWithValue(&start, &end, "ltfield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "ltfield") + +// errs = validate.FieldWithValue(timeTest, &end, "ltfield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "ltfield") + +// errs = validate.FieldWithValue("test", "tes", "ltfield") +// Equal(t, errs, nil) + +// type IntTest struct { +// Val1 int `validate:"required"` +// Val2 int `validate:"required,ltfield=Val1"` +// } + +// intTest := &IntTest{ +// Val1: 5, +// Val2: 1, +// } + +// errs = validate.Struct(intTest) +// Equal(t, errs, nil) + +// intTest = &IntTest{ +// Val1: 1, +// Val2: 5, +// } + +// errs = validate.Struct(intTest) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "IntTest.Val2", "Val2", "ltfield") + +// errs = validate.FieldWithValue(int(5), int(1), "ltfield") +// Equal(t, errs, nil) + +// errs = validate.FieldWithValue(int(1), int(5), "ltfield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "ltfield") + +// type UIntTest struct { +// Val1 uint `validate:"required"` +// Val2 uint `validate:"required,ltfield=Val1"` +// } + +// uIntTest := &UIntTest{ +// Val1: 5, +// Val2: 1, +// } + +// errs = validate.Struct(uIntTest) +// Equal(t, errs, nil) + +// uIntTest = &UIntTest{ +// Val1: 1, +// Val2: 5, +// } + +// errs = validate.Struct(uIntTest) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "UIntTest.Val2", "Val2", "ltfield") + +// errs = validate.FieldWithValue(uint(5), uint(1), "ltfield") +// Equal(t, errs, nil) + +// errs = validate.FieldWithValue(uint(1), uint(5), "ltfield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "ltfield") - errs = validate.FieldWithValue(now2, now, "eqcsfield") - Equal(t, errs, nil) +// type FloatTest struct { +// Val1 float64 `validate:"required"` +// Val2 float64 `validate:"required,ltfield=Val1"` +// } + +// floatTest := &FloatTest{ +// Val1: 5, +// Val2: 1, +// } + +// errs = validate.Struct(floatTest) +// Equal(t, errs, nil) + +// floatTest = &FloatTest{ +// Val1: 1, +// Val2: 5, +// } + +// errs = validate.Struct(floatTest) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "FloatTest.Val2", "Val2", "ltfield") + +// errs = validate.FieldWithValue(float32(5), float32(1), "ltfield") +// Equal(t, errs, nil) + +// errs = validate.FieldWithValue(float32(1), float32(5), "ltfield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "ltfield") + +// errs = validate.FieldWithValue(nil, 5, "ltfield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "ltfield") + +// errs = validate.FieldWithValue(1, "T", "ltfield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "ltfield") + +// errs = validate.FieldWithValue(1, end, "ltfield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "ltfield") + +// type TimeTest2 struct { +// Start *time.Time `validate:"required"` +// End *time.Time `validate:"required,ltfield=NonExistantField"` +// } + +// timeTest2 := &TimeTest2{ +// Start: &end, +// End: &start, +// } + +// errs = validate.Struct(timeTest2) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "TimeTest2.End", "End", "ltfield") +// } + +// func TestLteField(t *testing.T) { + +// type TimeTest struct { +// Start *time.Time `validate:"required,lte,ltefield=End"` +// End *time.Time `validate:"required,lte"` +// } + +// now := time.Now() +// start := now.Add(time.Hour * 24 * -1 * 2) +// end := start.Add(time.Hour * 24) + +// timeTest := &TimeTest{ +// Start: &start, +// End: &end, +// } + +// errs := validate.Struct(timeTest) +// Equal(t, errs, nil) + +// timeTest = &TimeTest{ +// Start: &end, +// End: &start, +// } + +// errs = validate.Struct(timeTest) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "TimeTest.Start", "Start", "ltefield") - errs = validate.FieldWithValue(arr3, arr, "eqcsfield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "eqcsfield") +// errs = validate.FieldWithValue(&end, &start, "ltefield") +// Equal(t, errs, nil) + +// errs = validate.FieldWithValue(&start, &end, "ltefield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "ltefield") + +// errs = validate.FieldWithValue(timeTest, &end, "ltefield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "ltefield") + +// errs = validate.FieldWithValue("test", "tes", "ltefield") +// Equal(t, errs, nil) + +// errs = validate.FieldWithValue("test", "test", "ltefield") +// Equal(t, errs, nil) + +// type IntTest struct { +// Val1 int `validate:"required"` +// Val2 int `validate:"required,ltefield=Val1"` +// } + +// intTest := &IntTest{ +// Val1: 5, +// Val2: 1, +// } + +// errs = validate.Struct(intTest) +// Equal(t, errs, nil) + +// intTest = &IntTest{ +// Val1: 1, +// Val2: 5, +// } + +// errs = validate.Struct(intTest) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "IntTest.Val2", "Val2", "ltefield") + +// errs = validate.FieldWithValue(int(5), int(1), "ltefield") +// Equal(t, errs, nil) + +// errs = validate.FieldWithValue(int(1), int(5), "ltefield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "ltefield") + +// type UIntTest struct { +// Val1 uint `validate:"required"` +// Val2 uint `validate:"required,ltefield=Val1"` +// } + +// uIntTest := &UIntTest{ +// Val1: 5, +// Val2: 1, +// } + +// errs = validate.Struct(uIntTest) +// Equal(t, errs, nil) + +// uIntTest = &UIntTest{ +// Val1: 1, +// Val2: 5, +// } + +// errs = validate.Struct(uIntTest) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "UIntTest.Val2", "Val2", "ltefield") + +// errs = validate.FieldWithValue(uint(5), uint(1), "ltefield") +// Equal(t, errs, nil) - type SInner struct { - Name string - } +// errs = validate.FieldWithValue(uint(1), uint(5), "ltefield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "ltefield") + +// type FloatTest struct { +// Val1 float64 `validate:"required"` +// Val2 float64 `validate:"required,ltefield=Val1"` +// } + +// floatTest := &FloatTest{ +// Val1: 5, +// Val2: 1, +// } + +// errs = validate.Struct(floatTest) +// Equal(t, errs, nil) - type TStruct struct { - Inner *SInner - CreatedAt *time.Time `validate:"eqcsfield=Inner"` - } +// floatTest = &FloatTest{ +// Val1: 1, +// Val2: 5, +// } + +// errs = validate.Struct(floatTest) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "FloatTest.Val2", "Val2", "ltefield") + +// errs = validate.FieldWithValue(float32(5), float32(1), "ltefield") +// Equal(t, errs, nil) - sinner := &SInner{ - Name: "NAME", - } +// errs = validate.FieldWithValue(float32(1), float32(5), "ltefield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "ltefield") + +// errs = validate.FieldWithValue(nil, 5, "ltefield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "ltefield") + +// errs = validate.FieldWithValue(1, "T", "ltefield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "ltefield") + +// errs = validate.FieldWithValue(1, end, "ltefield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "ltefield") + +// type TimeTest2 struct { +// Start *time.Time `validate:"required"` +// End *time.Time `validate:"required,ltefield=NonExistantField"` +// } + +// timeTest2 := &TimeTest2{ +// Start: &end, +// End: &start, +// } + +// errs = validate.Struct(timeTest2) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "TimeTest2.End", "End", "ltefield") +// } + +// func TestGteField(t *testing.T) { + +// type TimeTest struct { +// Start *time.Time `validate:"required,gte"` +// End *time.Time `validate:"required,gte,gtefield=Start"` +// } + +// now := time.Now() +// start := now.Add(time.Hour * 24) +// end := start.Add(time.Hour * 24) + +// timeTest := &TimeTest{ +// Start: &start, +// End: &end, +// } + +// errs := validate.Struct(timeTest) +// Equal(t, errs, nil) + +// timeTest = &TimeTest{ +// Start: &end, +// End: &start, +// } + +// errs = validate.Struct(timeTest) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "TimeTest.End", "End", "gtefield") - test2 := &TStruct{ - Inner: sinner, - CreatedAt: &now, - } +// errs = validate.FieldWithValue(&start, &end, "gtefield") +// Equal(t, errs, nil) + +// errs = validate.FieldWithValue(&end, &start, "gtefield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "gtefield") + +// errs = validate.FieldWithValue(timeTest, &start, "gtefield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "gtefield") + +// errs = validate.FieldWithValue("test", "test", "gtefield") +// Equal(t, errs, nil) + +// errs = validate.FieldWithValue("test", "test bigger", "gtefield") +// Equal(t, errs, nil) + +// type IntTest struct { +// Val1 int `validate:"required"` +// Val2 int `validate:"required,gtefield=Val1"` +// } + +// intTest := &IntTest{ +// Val1: 1, +// Val2: 5, +// } + +// errs = validate.Struct(intTest) +// Equal(t, errs, nil) + +// intTest = &IntTest{ +// Val1: 5, +// Val2: 1, +// } + +// errs = validate.Struct(intTest) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "IntTest.Val2", "Val2", "gtefield") + +// errs = validate.FieldWithValue(int(1), int(5), "gtefield") +// Equal(t, errs, nil) + +// errs = validate.FieldWithValue(int(5), int(1), "gtefield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "gtefield") - errs = validate.Struct(test2) - NotEqual(t, errs, nil) - AssertError(t, errs, "TStruct.CreatedAt", "CreatedAt", "eqcsfield") +// type UIntTest struct { +// Val1 uint `validate:"required"` +// Val2 uint `validate:"required,gtefield=Val1"` +// } - test2.Inner = nil - errs = validate.Struct(test2) - NotEqual(t, errs, nil) - AssertError(t, errs, "TStruct.CreatedAt", "CreatedAt", "eqcsfield") +// uIntTest := &UIntTest{ +// Val1: 1, +// Val2: 5, +// } - errs = validate.FieldWithValue(nil, 1, "eqcsfield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "eqcsfield") -} +// errs = validate.Struct(uIntTest) +// Equal(t, errs, nil) -func TestCrossNamespaceFieldValidation(t *testing.T) { +// uIntTest = &UIntTest{ +// Val1: 5, +// Val2: 1, +// } - type SliceStruct struct { - Name string - } +// errs = validate.Struct(uIntTest) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "UIntTest.Val2", "Val2", "gtefield") - type MapStruct struct { - Name string - } +// errs = validate.FieldWithValue(uint(1), uint(5), "gtefield") +// Equal(t, errs, nil) - type Inner struct { - CreatedAt *time.Time - Slice []string - SliceStructs []*SliceStruct - SliceSlice [][]string - SliceSliceStruct [][]*SliceStruct - SliceMap []map[string]string - Map map[string]string - MapMap map[string]map[string]string - MapStructs map[string]*SliceStruct - MapMapStruct map[string]map[string]*SliceStruct - MapSlice map[string][]string - MapInt map[int]string - MapInt8 map[int8]string - MapInt16 map[int16]string - MapInt32 map[int32]string - MapInt64 map[int64]string - MapUint map[uint]string - MapUint8 map[uint8]string - MapUint16 map[uint16]string - MapUint32 map[uint32]string - MapUint64 map[uint64]string - MapFloat32 map[float32]string - MapFloat64 map[float64]string - MapBool map[bool]string - } +// errs = validate.FieldWithValue(uint(5), uint(1), "gtefield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "gtefield") - type Test struct { - Inner *Inner - CreatedAt *time.Time - } +// type FloatTest struct { +// Val1 float64 `validate:"required"` +// Val2 float64 `validate:"required,gtefield=Val1"` +// } - now := time.Now() - - inner := &Inner{ - CreatedAt: &now, - Slice: []string{"val1", "val2", "val3"}, - SliceStructs: []*SliceStruct{{Name: "name1"}, {Name: "name2"}, {Name: "name3"}}, - SliceSlice: [][]string{{"1", "2", "3"}, {"4", "5", "6"}, {"7", "8", "9"}}, - SliceSliceStruct: [][]*SliceStruct{{{Name: "name1"}, {Name: "name2"}, {Name: "name3"}}, {{Name: "name4"}, {Name: "name5"}, {Name: "name6"}}, {{Name: "name7"}, {Name: "name8"}, {Name: "name9"}}}, - SliceMap: []map[string]string{{"key1": "val1", "key2": "val2", "key3": "val3"}, {"key4": "val4", "key5": "val5", "key6": "val6"}}, - Map: map[string]string{"key1": "val1", "key2": "val2", "key3": "val3"}, - MapStructs: map[string]*SliceStruct{"key1": {Name: "name1"}, "key2": {Name: "name2"}, "key3": {Name: "name3"}}, - MapMap: map[string]map[string]string{"key1": {"key1-1": "val1"}, "key2": {"key2-1": "val2"}, "key3": {"key3-1": "val3"}}, - MapMapStruct: map[string]map[string]*SliceStruct{"key1": {"key1-1": {Name: "name1"}}, "key2": {"key2-1": {Name: "name2"}}, "key3": {"key3-1": {Name: "name3"}}}, - MapSlice: map[string][]string{"key1": {"1", "2", "3"}, "key2": {"4", "5", "6"}, "key3": {"7", "8", "9"}}, - MapInt: map[int]string{1: "val1", 2: "val2", 3: "val3"}, - MapInt8: map[int8]string{1: "val1", 2: "val2", 3: "val3"}, - MapInt16: map[int16]string{1: "val1", 2: "val2", 3: "val3"}, - MapInt32: map[int32]string{1: "val1", 2: "val2", 3: "val3"}, - MapInt64: map[int64]string{1: "val1", 2: "val2", 3: "val3"}, - MapUint: map[uint]string{1: "val1", 2: "val2", 3: "val3"}, - MapUint8: map[uint8]string{1: "val1", 2: "val2", 3: "val3"}, - MapUint16: map[uint16]string{1: "val1", 2: "val2", 3: "val3"}, - MapUint32: map[uint32]string{1: "val1", 2: "val2", 3: "val3"}, - MapUint64: map[uint64]string{1: "val1", 2: "val2", 3: "val3"}, - MapFloat32: map[float32]string{1.01: "val1", 2.02: "val2", 3.03: "val3"}, - MapFloat64: map[float64]string{1.01: "val1", 2.02: "val2", 3.03: "val3"}, - MapBool: map[bool]string{true: "val1", false: "val2"}, - } +// floatTest := &FloatTest{ +// Val1: 1, +// Val2: 5, +// } - test := &Test{ - Inner: inner, - CreatedAt: &now, - } +// errs = validate.Struct(floatTest) +// Equal(t, errs, nil) - val := reflect.ValueOf(test) - - current, kind, ok := validate.GetStructFieldOK(val, "Inner.CreatedAt") - Equal(t, ok, true) - Equal(t, kind, reflect.Struct) - tm, ok := current.Interface().(time.Time) - Equal(t, ok, true) - Equal(t, tm, now) - - current, kind, ok = validate.GetStructFieldOK(val, "Inner.Slice[1]") - Equal(t, ok, true) - Equal(t, kind, reflect.String) - Equal(t, current.String(), "val2") - - current, kind, ok = validate.GetStructFieldOK(val, "Inner.CrazyNonExistantField") - Equal(t, ok, false) - - current, kind, ok = validate.GetStructFieldOK(val, "Inner.Slice[101]") - Equal(t, ok, false) - - current, kind, ok = validate.GetStructFieldOK(val, "Inner.Map[key3]") - Equal(t, ok, true) - Equal(t, kind, reflect.String) - Equal(t, current.String(), "val3") - - current, kind, ok = validate.GetStructFieldOK(val, "Inner.MapMap[key2][key2-1]") - Equal(t, ok, true) - Equal(t, kind, reflect.String) - Equal(t, current.String(), "val2") - - current, kind, ok = validate.GetStructFieldOK(val, "Inner.MapStructs[key2].Name") - Equal(t, ok, true) - Equal(t, kind, reflect.String) - Equal(t, current.String(), "name2") - - current, kind, ok = validate.GetStructFieldOK(val, "Inner.MapMapStruct[key3][key3-1].Name") - Equal(t, ok, true) - Equal(t, kind, reflect.String) - Equal(t, current.String(), "name3") - - current, kind, ok = validate.GetStructFieldOK(val, "Inner.SliceSlice[2][0]") - Equal(t, ok, true) - Equal(t, kind, reflect.String) - Equal(t, current.String(), "7") - - current, kind, ok = validate.GetStructFieldOK(val, "Inner.SliceSliceStruct[2][1].Name") - Equal(t, ok, true) - Equal(t, kind, reflect.String) - Equal(t, current.String(), "name8") - - current, kind, ok = validate.GetStructFieldOK(val, "Inner.SliceMap[1][key5]") - Equal(t, ok, true) - Equal(t, kind, reflect.String) - Equal(t, current.String(), "val5") - - current, kind, ok = validate.GetStructFieldOK(val, "Inner.MapSlice[key3][2]") - Equal(t, ok, true) - Equal(t, kind, reflect.String) - Equal(t, current.String(), "9") - - current, kind, ok = validate.GetStructFieldOK(val, "Inner.MapInt[2]") - Equal(t, ok, true) - Equal(t, kind, reflect.String) - Equal(t, current.String(), "val2") - - current, kind, ok = validate.GetStructFieldOK(val, "Inner.MapInt8[2]") - Equal(t, ok, true) - Equal(t, kind, reflect.String) - Equal(t, current.String(), "val2") - - current, kind, ok = validate.GetStructFieldOK(val, "Inner.MapInt16[2]") - Equal(t, ok, true) - Equal(t, kind, reflect.String) - Equal(t, current.String(), "val2") - - current, kind, ok = validate.GetStructFieldOK(val, "Inner.MapInt32[2]") - Equal(t, ok, true) - Equal(t, kind, reflect.String) - Equal(t, current.String(), "val2") - - current, kind, ok = validate.GetStructFieldOK(val, "Inner.MapInt64[2]") - Equal(t, ok, true) - Equal(t, kind, reflect.String) - Equal(t, current.String(), "val2") - - current, kind, ok = validate.GetStructFieldOK(val, "Inner.MapUint[2]") - Equal(t, ok, true) - Equal(t, kind, reflect.String) - Equal(t, current.String(), "val2") - - current, kind, ok = validate.GetStructFieldOK(val, "Inner.MapUint8[2]") - Equal(t, ok, true) - Equal(t, kind, reflect.String) - Equal(t, current.String(), "val2") - - current, kind, ok = validate.GetStructFieldOK(val, "Inner.MapUint16[2]") - Equal(t, ok, true) - Equal(t, kind, reflect.String) - Equal(t, current.String(), "val2") - - current, kind, ok = validate.GetStructFieldOK(val, "Inner.MapUint32[2]") - Equal(t, ok, true) - Equal(t, kind, reflect.String) - Equal(t, current.String(), "val2") - - current, kind, ok = validate.GetStructFieldOK(val, "Inner.MapUint64[2]") - Equal(t, ok, true) - Equal(t, kind, reflect.String) - Equal(t, current.String(), "val2") - - current, kind, ok = validate.GetStructFieldOK(val, "Inner.MapFloat32[3.03]") - Equal(t, ok, true) - Equal(t, kind, reflect.String) - Equal(t, current.String(), "val3") - - current, kind, ok = validate.GetStructFieldOK(val, "Inner.MapFloat64[2.02]") - Equal(t, ok, true) - Equal(t, kind, reflect.String) - Equal(t, current.String(), "val2") - - current, kind, ok = validate.GetStructFieldOK(val, "Inner.MapBool[true]") - Equal(t, ok, true) - Equal(t, kind, reflect.String) - Equal(t, current.String(), "val1") - - inner = &Inner{ - CreatedAt: &now, - Slice: []string{"val1", "val2", "val3"}, - SliceStructs: []*SliceStruct{{Name: "name1"}, {Name: "name2"}, nil}, - SliceSlice: [][]string{{"1", "2", "3"}, {"4", "5", "6"}, {"7", "8", "9"}}, - SliceSliceStruct: [][]*SliceStruct{{{Name: "name1"}, {Name: "name2"}, {Name: "name3"}}, {{Name: "name4"}, {Name: "name5"}, {Name: "name6"}}, {{Name: "name7"}, {Name: "name8"}, {Name: "name9"}}}, - SliceMap: []map[string]string{{"key1": "val1", "key2": "val2", "key3": "val3"}, {"key4": "val4", "key5": "val5", "key6": "val6"}}, - Map: map[string]string{"key1": "val1", "key2": "val2", "key3": "val3"}, - MapStructs: map[string]*SliceStruct{"key1": {Name: "name1"}, "key2": {Name: "name2"}, "key3": {Name: "name3"}}, - MapMap: map[string]map[string]string{"key1": {"key1-1": "val1"}, "key2": {"key2-1": "val2"}, "key3": {"key3-1": "val3"}}, - MapMapStruct: map[string]map[string]*SliceStruct{"key1": {"key1-1": {Name: "name1"}}, "key2": {"key2-1": {Name: "name2"}}, "key3": {"key3-1": {Name: "name3"}}}, - MapSlice: map[string][]string{"key1": {"1", "2", "3"}, "key2": {"4", "5", "6"}, "key3": {"7", "8", "9"}}, - } +// floatTest = &FloatTest{ +// Val1: 5, +// Val2: 1, +// } - test = &Test{ - Inner: inner, - CreatedAt: nil, - } +// errs = validate.Struct(floatTest) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "FloatTest.Val2", "Val2", "gtefield") - val = reflect.ValueOf(test) +// errs = validate.FieldWithValue(float32(1), float32(5), "gtefield") +// Equal(t, errs, nil) - current, kind, ok = validate.GetStructFieldOK(val, "Inner.SliceStructs[2]") - Equal(t, ok, true) - Equal(t, kind, reflect.Ptr) - Equal(t, current.String(), "<*validator.SliceStruct Value>") - Equal(t, current.IsNil(), true) +// errs = validate.FieldWithValue(float32(5), float32(1), "gtefield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "gtefield") - current, kind, ok = validate.GetStructFieldOK(val, "Inner.SliceStructs[2].Name") - Equal(t, ok, false) - Equal(t, kind, reflect.Ptr) - Equal(t, current.String(), "<*validator.SliceStruct Value>") - Equal(t, current.IsNil(), true) +// errs = validate.FieldWithValue(nil, 1, "gtefield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "gtefield") - PanicMatches(t, func() { validate.GetStructFieldOK(reflect.ValueOf(1), "crazyinput") }, "Invalid field namespace") -} +// errs = validate.FieldWithValue(5, "T", "gtefield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "gtefield") -func TestExistsValidation(t *testing.T) { +// errs = validate.FieldWithValue(5, start, "gtefield") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "gtefield") - jsonText := "{ \"truthiness2\": true }" +// type TimeTest2 struct { +// Start *time.Time `validate:"required"` +// End *time.Time `validate:"required,gtefield=NonExistantField"` +// } - type Thing struct { - Truthiness *bool `json:"truthiness" validate:"exists,required"` - } +// timeTest2 := &TimeTest2{ +// Start: &start, +// End: &end, +// } - var ting Thing +// errs = validate.Struct(timeTest2) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "TimeTest2.End", "End", "gtefield") +// } - err := json.Unmarshal([]byte(jsonText), &ting) - Equal(t, err, nil) - NotEqual(t, ting, nil) - Equal(t, ting.Truthiness, nil) +// func TestValidateByTagAndValue(t *testing.T) { - errs := validate.Struct(ting) - NotEqual(t, errs, nil) - AssertError(t, errs, "Thing.Truthiness", "Truthiness", "exists") +// val := "test" +// field := "test" +// errs := validate.FieldWithValue(val, field, "required") +// Equal(t, errs, nil) - jsonText = "{ \"truthiness\": true }" +// fn := func(v *Validate, topStruct reflect.Value, current reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - err = json.Unmarshal([]byte(jsonText), &ting) - Equal(t, err, nil) - NotEqual(t, ting, nil) - Equal(t, ting.Truthiness, true) +// return current.String() == field.String() +// } - errs = validate.Struct(ting) - Equal(t, errs, nil) -} +// validate.RegisterValidation("isequaltestfunc", fn) -func TestSQLValue2Validation(t *testing.T) { +// errs = validate.FieldWithValue(val, field, "isequaltestfunc") +// Equal(t, errs, nil) - config := &Config{ - TagName: "validate", - } +// val = "unequal" - validate := New(config) - validate.RegisterCustomTypeFunc(ValidateValuerType, valuer{}, (*driver.Valuer)(nil), sql.NullString{}, sql.NullInt64{}, sql.NullBool{}, sql.NullFloat64{}) - validate.RegisterCustomTypeFunc(ValidateCustomType, MadeUpCustomType{}) - validate.RegisterCustomTypeFunc(OverrideIntTypeForSomeReason, 1) +// errs = validate.FieldWithValue(val, field, "isequaltestfunc") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "isequaltestfunc") +// } - val := valuer{ - Name: "", - } +// func TestAddFunctions(t *testing.T) { - errs := validate.Field(val, "required") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "required") +// fn := func(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - val.Name = "Valid Name" - errs = validate.Field(val, "required") - Equal(t, errs, nil) +// return true +// } - val.Name = "errorme" +// config := &Config{ +// TagName: "validateme", +// } - PanicMatches(t, func() { validate.Field(val, "required") }, "SQL Driver Valuer error: some kind of error") +// validate := New(config) - type myValuer valuer +// errs := validate.RegisterValidation("new", fn) +// Equal(t, errs, nil) - myVal := valuer{ - Name: "", - } +// errs = validate.RegisterValidation("", fn) +// NotEqual(t, errs, nil) - errs = validate.Field(myVal, "required") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "required") +// validate.RegisterValidation("new", nil) +// NotEqual(t, errs, nil) - cust := MadeUpCustomType{ - FirstName: "Joey", - LastName: "Bloggs", - } +// errs = validate.RegisterValidation("new", fn) +// Equal(t, errs, nil) - c := CustomMadeUpStruct{MadeUp: cust, OverriddenInt: 2} +// PanicMatches(t, func() { validate.RegisterValidation("dive", fn) }, "Tag 'dive' either contains restricted characters or is the same as a restricted tag needed for normal operation") +// } - errs = validate.Struct(c) - Equal(t, errs, nil) +// func TestChangeTag(t *testing.T) { - c.MadeUp.FirstName = "" - c.OverriddenInt = 1 +// config := &Config{ +// TagName: "val", +// } +// validate := New(config) - errs = validate.Struct(c) - NotEqual(t, errs, nil) - Equal(t, len(errs.(ValidationErrors)), 2) - AssertError(t, errs, "CustomMadeUpStruct.MadeUp", "MadeUp", "required") - AssertError(t, errs, "CustomMadeUpStruct.OverriddenInt", "OverriddenInt", "gt") -} +// type Test struct { +// Name string `val:"len=4"` +// } +// s := &Test{ +// Name: "TEST", +// } -func TestSQLValueValidation(t *testing.T) { +// errs := validate.Struct(s) +// Equal(t, errs, nil) +// } - validate := New(&Config{TagName: "validate"}) - validate.RegisterCustomTypeFunc(ValidateValuerType, (*driver.Valuer)(nil), valuer{}) - validate.RegisterCustomTypeFunc(ValidateCustomType, MadeUpCustomType{}) - validate.RegisterCustomTypeFunc(OverrideIntTypeForSomeReason, 1) +// func TestUnexposedStruct(t *testing.T) { - val := valuer{ - Name: "", - } +// type Test struct { +// Name string +// unexposed struct { +// A string `validate:"required"` +// } +// } - errs := validate.Field(val, "required") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "required") +// s := &Test{ +// Name: "TEST", +// } - val.Name = "Valid Name" - errs = validate.Field(val, "required") - Equal(t, errs, nil) +// errs := validate.Struct(s) +// Equal(t, errs, nil) +// } - val.Name = "errorme" +// func TestBadParams(t *testing.T) { - PanicMatches(t, func() { errs = validate.Field(val, "required") }, "SQL Driver Valuer error: some kind of error") +// i := 1 +// errs := validate.Field(i, "-") +// Equal(t, errs, nil) - type myValuer valuer +// PanicMatches(t, func() { validate.Field(i, "len=a") }, "strconv.ParseInt: parsing \"a\": invalid syntax") +// PanicMatches(t, func() { validate.Field(i, "len=a") }, "strconv.ParseInt: parsing \"a\": invalid syntax") - myVal := valuer{ - Name: "", - } +// var ui uint = 1 +// PanicMatches(t, func() { validate.Field(ui, "len=a") }, "strconv.ParseUint: parsing \"a\": invalid syntax") - errs = validate.Field(myVal, "required") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "required") +// f := 1.23 +// PanicMatches(t, func() { validate.Field(f, "len=a") }, "strconv.ParseFloat: parsing \"a\": invalid syntax") +// } - cust := MadeUpCustomType{ - FirstName: "Joey", - LastName: "Bloggs", - } +// func TestLength(t *testing.T) { - c := CustomMadeUpStruct{MadeUp: cust, OverriddenInt: 2} +// i := true +// PanicMatches(t, func() { validate.Field(i, "len") }, "Bad field type bool") +// } - errs = validate.Struct(c) - Equal(t, errs, nil) +// func TestIsGt(t *testing.T) { - c.MadeUp.FirstName = "" - c.OverriddenInt = 1 +// myMap := map[string]string{} +// errs := validate.Field(myMap, "gt=0") +// NotEqual(t, errs, nil) - errs = validate.Struct(c) - NotEqual(t, errs, nil) - Equal(t, len(errs.(ValidationErrors)), 2) - AssertError(t, errs, "CustomMadeUpStruct.MadeUp", "MadeUp", "required") - AssertError(t, errs, "CustomMadeUpStruct.OverriddenInt", "OverriddenInt", "gt") -} +// f := 1.23 +// errs = validate.Field(f, "gt=5") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "gt") -func TestMACValidation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"3D:F2:C9:A6:B3:4F", true}, - {"3D-F2-C9-A6-B3:4F", false}, - {"123", false}, - {"", false}, - {"abacaba", false}, - {"00:25:96:FF:FE:12:34:56", true}, - {"0025:96FF:FE12:3456", false}, - } +// var ui uint = 5 +// errs = validate.Field(ui, "gt=10") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "gt") - for i, test := range tests { - - errs := validate.Field(test.param, "mac") - - if test.expected { - if !IsEqual(errs, nil) { - t.Fatalf("Index: %d mac failed Error: %s", i, errs) - } - } else { - if IsEqual(errs, nil) { - t.Fatalf("Index: %d mac failed Error: %s", i, errs) - } else { - val := errs.(ValidationErrors)[""] - if val.Tag != "mac" { - t.Fatalf("Index: %d mac failed Error: %s", i, errs) - } - } - } - } -} +// i := true +// PanicMatches(t, func() { validate.Field(i, "gt") }, "Bad field type bool") -func TestIPValidation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"", false}, - {"10.0.0.1", true}, - {"172.16.0.1", true}, - {"192.168.0.1", true}, - {"192.168.255.254", true}, - {"192.168.255.256", false}, - {"172.16.255.254", true}, - {"172.16.256.255", false}, - {"2001:cdba:0000:0000:0000:0000:3257:9652", true}, - {"2001:cdba:0:0:0:0:3257:9652", true}, - {"2001:cdba::3257:9652", true}, - } +// tm := time.Now().UTC() +// tm = tm.Add(time.Hour * 24) - for i, test := range tests { - - errs := validate.Field(test.param, "ip") - - if test.expected { - if !IsEqual(errs, nil) { - t.Fatalf("Index: %d ip failed Error: %s", i, errs) - } - } else { - if IsEqual(errs, nil) { - t.Fatalf("Index: %d ip failed Error: %s", i, errs) - } else { - val := errs.(ValidationErrors)[""] - if val.Tag != "ip" { - t.Fatalf("Index: %d ip failed Error: %s", i, errs) - } - } - } - } -} +// errs = validate.Field(tm, "gt") +// Equal(t, errs, nil) -func TestIPv6Validation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"10.0.0.1", false}, - {"172.16.0.1", false}, - {"192.168.0.1", false}, - {"192.168.255.254", false}, - {"192.168.255.256", false}, - {"172.16.255.254", false}, - {"172.16.256.255", false}, - {"2001:cdba:0000:0000:0000:0000:3257:9652", true}, - {"2001:cdba:0:0:0:0:3257:9652", true}, - {"2001:cdba::3257:9652", true}, - } +// t2 := time.Now().UTC() - for i, test := range tests { - - errs := validate.Field(test.param, "ipv6") - - if test.expected { - if !IsEqual(errs, nil) { - t.Fatalf("Index: %d ipv6 failed Error: %s", i, errs) - } - } else { - if IsEqual(errs, nil) { - t.Fatalf("Index: %d ipv6 failed Error: %s", i, errs) - } else { - val := errs.(ValidationErrors)[""] - if val.Tag != "ipv6" { - t.Fatalf("Index: %d ipv6 failed Error: %s", i, errs) - } - } - } - } -} - -func TestIPv4Validation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"10.0.0.1", true}, - {"172.16.0.1", true}, - {"192.168.0.1", true}, - {"192.168.255.254", true}, - {"192.168.255.256", false}, - {"172.16.255.254", true}, - {"172.16.256.255", false}, - {"2001:cdba:0000:0000:0000:0000:3257:9652", false}, - {"2001:cdba:0:0:0:0:3257:9652", false}, - {"2001:cdba::3257:9652", false}, - } - - for i, test := range tests { - - errs := validate.Field(test.param, "ipv4") - - if test.expected { - if !IsEqual(errs, nil) { - t.Fatalf("Index: %d ipv4 failed Error: %s", i, errs) - } - } else { - if IsEqual(errs, nil) { - t.Fatalf("Index: %d ipv4 failed Error: %s", i, errs) - } else { - val := errs.(ValidationErrors)[""] - if val.Tag != "ipv4" { - t.Fatalf("Index: %d ipv4 failed Error: %s", i, errs) - } - } - } - } -} - -func TestCIDRValidation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"10.0.0.0/0", true}, - {"10.0.0.1/8", true}, - {"172.16.0.1/16", true}, - {"192.168.0.1/24", true}, - {"192.168.255.254/24", true}, - {"192.168.255.254/48", false}, - {"192.168.255.256/24", false}, - {"172.16.255.254/16", true}, - {"172.16.256.255/16", false}, - {"2001:cdba:0000:0000:0000:0000:3257:9652/64", true}, - {"2001:cdba:0000:0000:0000:0000:3257:9652/256", false}, - {"2001:cdba:0:0:0:0:3257:9652/32", true}, - {"2001:cdba::3257:9652/16", true}, - } - - for i, test := range tests { - - errs := validate.Field(test.param, "cidr") - - if test.expected { - if !IsEqual(errs, nil) { - t.Fatalf("Index: %d cidr failed Error: %s", i, errs) - } - } else { - if IsEqual(errs, nil) { - t.Fatalf("Index: %d cidr failed Error: %s", i, errs) - } else { - val := errs.(ValidationErrors)[""] - if val.Tag != "cidr" { - t.Fatalf("Index: %d cidr failed Error: %s", i, errs) - } - } - } - } -} - -func TestCIDRv6Validation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"10.0.0.0/0", false}, - {"10.0.0.1/8", false}, - {"172.16.0.1/16", false}, - {"192.168.0.1/24", false}, - {"192.168.255.254/24", false}, - {"192.168.255.254/48", false}, - {"192.168.255.256/24", false}, - {"172.16.255.254/16", false}, - {"172.16.256.255/16", false}, - {"2001:cdba:0000:0000:0000:0000:3257:9652/64", true}, - {"2001:cdba:0000:0000:0000:0000:3257:9652/256", false}, - {"2001:cdba:0:0:0:0:3257:9652/32", true}, - {"2001:cdba::3257:9652/16", true}, - } - - for i, test := range tests { - - errs := validate.Field(test.param, "cidrv6") - - if test.expected { - if !IsEqual(errs, nil) { - t.Fatalf("Index: %d cidrv6 failed Error: %s", i, errs) - } - } else { - if IsEqual(errs, nil) { - t.Fatalf("Index: %d cidrv6 failed Error: %s", i, errs) - } else { - val := errs.(ValidationErrors)[""] - if val.Tag != "cidrv6" { - t.Fatalf("Index: %d cidrv6 failed Error: %s", i, errs) - } - } - } - } -} - -func TestCIDRv4Validation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"10.0.0.0/0", true}, - {"10.0.0.1/8", true}, - {"172.16.0.1/16", true}, - {"192.168.0.1/24", true}, - {"192.168.255.254/24", true}, - {"192.168.255.254/48", false}, - {"192.168.255.256/24", false}, - {"172.16.255.254/16", true}, - {"172.16.256.255/16", false}, - {"2001:cdba:0000:0000:0000:0000:3257:9652/64", false}, - {"2001:cdba:0000:0000:0000:0000:3257:9652/256", false}, - {"2001:cdba:0:0:0:0:3257:9652/32", false}, - {"2001:cdba::3257:9652/16", false}, - } - - for i, test := range tests { - - errs := validate.Field(test.param, "cidrv4") - - if test.expected { - if !IsEqual(errs, nil) { - t.Fatalf("Index: %d cidrv4 failed Error: %s", i, errs) - } - } else { - if IsEqual(errs, nil) { - t.Fatalf("Index: %d cidrv4 failed Error: %s", i, errs) - } else { - val := errs.(ValidationErrors)[""] - if val.Tag != "cidrv4" { - t.Fatalf("Index: %d cidrv4 failed Error: %s", i, errs) - } - } - } - } -} - -func TestTCPAddrValidation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"", false}, - {":80", false}, - {"127.0.0.1:80", true}, - {"[::1]:80", true}, - {"256.0.0.0:1", false}, - {"[::1]", false}, - } - - for i, test := range tests { - errs := validate.Field(test.param, "tcp_addr") - if test.expected { - if !IsEqual(errs, nil) { - t.Fatalf("Index: %d tcp_addr failed Error: %s", i, errs) - } - } else { - if IsEqual(errs, nil) { - t.Fatalf("Index: %d tcp_addr failed Error: %s", i, errs) - } else { - val := errs.(ValidationErrors)[""] - if val.Tag != "tcp_addr" { - t.Fatalf("Index: %d tcp_addr failed Error: %s", i, errs) - } - } - } - } -} - -func TestTCP6AddrValidation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"", false}, - {":80", false}, - {"127.0.0.1:80", false}, - {"[::1]:80", true}, - {"256.0.0.0:1", false}, - {"[::1]", false}, - } - - for i, test := range tests { - errs := validate.Field(test.param, "tcp6_addr") - if test.expected { - if !IsEqual(errs, nil) { - t.Fatalf("Index: %d tcp6_addr failed Error: %s", i, errs) - } - } else { - if IsEqual(errs, nil) { - t.Fatalf("Index: %d tcp6_addr failed Error: %s", i, errs) - } else { - val := errs.(ValidationErrors)[""] - if val.Tag != "tcp6_addr" { - t.Fatalf("Index: %d tcp6_addr failed Error: %s", i, errs) - } - } - } - } -} - -func TestTCP4AddrValidation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"", false}, - {":80", false}, - {"127.0.0.1:80", true}, - {"[::1]:80", false}, // https://github.com/golang/go/issues/14037 - {"256.0.0.0:1", false}, - {"[::1]", false}, - } - - for i, test := range tests { - errs := validate.Field(test.param, "tcp4_addr") - if test.expected { - if !IsEqual(errs, nil) { - t.Fatalf("Index: %d tcp4_addr failed Error: %s", i, errs) - } - } else { - if IsEqual(errs, nil) { - t.Log(test.param, IsEqual(errs, nil)) - t.Fatalf("Index: %d tcp4_addr failed Error: %s", i, errs) - } else { - val := errs.(ValidationErrors)[""] - if val.Tag != "tcp4_addr" { - t.Fatalf("Index: %d tcp4_addr failed Error: %s", i, errs) - } - } - } - } -} - -func TestUDPAddrValidation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"", false}, - {":80", false}, - {"127.0.0.1:80", true}, - {"[::1]:80", true}, - {"256.0.0.0:1", false}, - {"[::1]", false}, - } - - for i, test := range tests { - errs := validate.Field(test.param, "udp_addr") - if test.expected { - if !IsEqual(errs, nil) { - t.Fatalf("Index: %d udp_addr failed Error: %s", i, errs) - } - } else { - if IsEqual(errs, nil) { - t.Fatalf("Index: %d udp_addr failed Error: %s", i, errs) - } else { - val := errs.(ValidationErrors)[""] - if val.Tag != "udp_addr" { - t.Fatalf("Index: %d udp_addr failed Error: %s", i, errs) - } - } - } - } -} - -func TestUDP6AddrValidation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"", false}, - {":80", false}, - {"127.0.0.1:80", false}, - {"[::1]:80", true}, - {"256.0.0.0:1", false}, - {"[::1]", false}, - } - - for i, test := range tests { - errs := validate.Field(test.param, "udp6_addr") - if test.expected { - if !IsEqual(errs, nil) { - t.Fatalf("Index: %d udp6_addr failed Error: %s", i, errs) - } - } else { - if IsEqual(errs, nil) { - t.Fatalf("Index: %d udp6_addr failed Error: %s", i, errs) - } else { - val := errs.(ValidationErrors)[""] - if val.Tag != "udp6_addr" { - t.Fatalf("Index: %d udp6_addr failed Error: %s", i, errs) - } - } - } - } -} - -func TestUDP4AddrValidation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"", false}, - {":80", false}, - {"127.0.0.1:80", true}, - {"[::1]:80", false}, // https://github.com/golang/go/issues/14037 - {"256.0.0.0:1", false}, - {"[::1]", false}, - } - - for i, test := range tests { - errs := validate.Field(test.param, "udp4_addr") - if test.expected { - if !IsEqual(errs, nil) { - t.Fatalf("Index: %d udp4_addr failed Error: %s", i, errs) - } - } else { - if IsEqual(errs, nil) { - t.Log(test.param, IsEqual(errs, nil)) - t.Fatalf("Index: %d udp4_addr failed Error: %s", i, errs) - } else { - val := errs.(ValidationErrors)[""] - if val.Tag != "udp4_addr" { - t.Fatalf("Index: %d udp4_addr failed Error: %s", i, errs) - } - } - } - } -} - -func TestIPAddrValidation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"", false}, - {"127.0.0.1", true}, - {"127.0.0.1:80", false}, - {"::1", true}, - {"256.0.0.0", false}, - {"localhost", false}, - } - - for i, test := range tests { - errs := validate.Field(test.param, "ip_addr") - if test.expected { - if !IsEqual(errs, nil) { - t.Fatalf("Index: %d ip_addr failed Error: %s", i, errs) - } - } else { - if IsEqual(errs, nil) { - t.Fatalf("Index: %d ip_addr failed Error: %s", i, errs) - } else { - val := errs.(ValidationErrors)[""] - if val.Tag != "ip_addr" { - t.Fatalf("Index: %d ip_addr failed Error: %s", i, errs) - } - } - } - } -} - -func TestIP6AddrValidation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"", false}, - {"127.0.0.1", false}, // https://github.com/golang/go/issues/14037 - {"127.0.0.1:80", false}, - {"::1", true}, - {"0:0:0:0:0:0:0:1", true}, - {"256.0.0.0", false}, - } - - for i, test := range tests { - errs := validate.Field(test.param, "ip6_addr") - if test.expected { - if !IsEqual(errs, nil) { - t.Fatalf("Index: %d ip6_addr failed Error: %s", i, errs) - } - } else { - if IsEqual(errs, nil) { - t.Fatalf("Index: %d ip6_addr failed Error: %s", i, errs) - } else { - val := errs.(ValidationErrors)[""] - if val.Tag != "ip6_addr" { - t.Fatalf("Index: %d ip6_addr failed Error: %s", i, errs) - } - } - } - } -} - -func TestIP4AddrValidation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"", false}, - {"127.0.0.1", true}, - {"127.0.0.1:80", false}, - {"::1", false}, // https://github.com/golang/go/issues/14037 - {"256.0.0.0", false}, - {"localhost", false}, - } - - for i, test := range tests { - errs := validate.Field(test.param, "ip4_addr") - if test.expected { - if !IsEqual(errs, nil) { - t.Fatalf("Index: %d ip4_addr failed Error: %s", i, errs) - } - } else { - if IsEqual(errs, nil) { - t.Log(test.param, IsEqual(errs, nil)) - t.Fatalf("Index: %d ip4_addr failed Error: %s", i, errs) - } else { - val := errs.(ValidationErrors)[""] - if val.Tag != "ip4_addr" { - t.Fatalf("Index: %d ip4_addr failed Error: %s", i, errs) - } - } - } - } -} - -func TestUnixAddrValidation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"", true}, - {"v.sock", true}, - } - - for i, test := range tests { - errs := validate.Field(test.param, "unix_addr") - if test.expected { - if !IsEqual(errs, nil) { - t.Fatalf("Index: %d unix_addr failed Error: %s", i, errs) - } - } else { - if IsEqual(errs, nil) { - t.Log(test.param, IsEqual(errs, nil)) - t.Fatalf("Index: %d unix_addr failed Error: %s", i, errs) - } else { - val := errs.(ValidationErrors)[""] - if val.Tag != "unix_addr" { - t.Fatalf("Index: %d unix_addr failed Error: %s", i, errs) - } - } - } - } -} - -func TestSliceMapArrayChanFuncPtrInterfaceRequiredValidation(t *testing.T) { - - var m map[string]string - - errs := validate.Field(m, "required") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "required") - - m = map[string]string{} - errs = validate.Field(m, "required") - Equal(t, errs, nil) - - var arr [5]string - errs = validate.Field(arr, "required") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "required") - - arr[0] = "ok" - errs = validate.Field(arr, "required") - Equal(t, errs, nil) - - var s []string - errs = validate.Field(s, "required") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "required") - - s = []string{} - errs = validate.Field(s, "required") - Equal(t, errs, nil) - - var c chan string - errs = validate.Field(c, "required") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "required") - - c = make(chan string) - errs = validate.Field(c, "required") - Equal(t, errs, nil) - - var tst *int - errs = validate.Field(tst, "required") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "required") - - one := 1 - tst = &one - errs = validate.Field(tst, "required") - Equal(t, errs, nil) - - var iface interface{} - - errs = validate.Field(iface, "required") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "required") - - errs = validate.Field(iface, "omitempty,required") - Equal(t, errs, nil) - - errs = validate.Field(iface, "") - Equal(t, errs, nil) - - errs = validate.FieldWithValue(nil, iface, "") - Equal(t, errs, nil) - - var f func(string) - - errs = validate.Field(f, "required") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "required") - - f = func(name string) {} - - errs = validate.Field(f, "required") - Equal(t, errs, nil) -} - -func TestDatePtrValidationIssueValidation(t *testing.T) { - - type Test struct { - LastViewed *time.Time - Reminder *time.Time - } - - test := &Test{} - - errs := validate.Struct(test) - Equal(t, errs, nil) -} - -func TestCommaAndPipeObfuscationValidation(t *testing.T) { - s := "My Name Is, |joeybloggs|" - - errs := validate.Field(s, "excludesall=0x2C") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "excludesall") - - errs = validate.Field(s, "excludesall=0x7C") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "excludesall") -} - -func TestBadKeyValidation(t *testing.T) { - type Test struct { - Name string `validate:"required, "` - } - - tst := &Test{ - Name: "test", - } - - PanicMatches(t, func() { validate.Struct(tst) }, "Undefined validation function on field Name") - - type Test2 struct { - Name string `validate:"required,,len=2"` - } - - tst2 := &Test2{ - Name: "test", - } - - PanicMatches(t, func() { validate.Struct(tst2) }, "Invalid validation tag on field Name") -} - -func TestInterfaceErrValidation(t *testing.T) { - - var v1 interface{} - var v2 interface{} - - v2 = 1 - v1 = v2 - - errs := validate.Field(v1, "len=1") - Equal(t, errs, nil) - - errs = validate.Field(v2, "len=1") - Equal(t, errs, nil) - - type ExternalCMD struct { - Userid string `json:"userid"` - Action uint32 `json:"action"` - Data interface{} `json:"data,omitempty" validate:"required"` - } - - s := &ExternalCMD{ - Userid: "123456", - Action: 10000, - // Data: 1, - } - - errs = validate.Struct(s) - NotEqual(t, errs, nil) - Equal(t, len(errs.(ValidationErrors)), 1) - AssertError(t, errs, "ExternalCMD.Data", "Data", "required") - - type ExternalCMD2 struct { - Userid string `json:"userid"` - Action uint32 `json:"action"` - Data interface{} `json:"data,omitempty" validate:"len=1"` - } - - s2 := &ExternalCMD2{ - Userid: "123456", - Action: 10000, - // Data: 1, - } - - errs = validate.Struct(s2) - NotEqual(t, errs, nil) - Equal(t, len(errs.(ValidationErrors)), 1) - AssertError(t, errs, "ExternalCMD2.Data", "Data", "len") - - s3 := &ExternalCMD2{ - Userid: "123456", - Action: 10000, - Data: 2, - } - - errs = validate.Struct(s3) - NotEqual(t, errs, nil) - Equal(t, len(errs.(ValidationErrors)), 1) - AssertError(t, errs, "ExternalCMD2.Data", "Data", "len") - - type Inner struct { - Name string `validate:"required"` - } - - inner := &Inner{ - Name: "", - } - - s4 := &ExternalCMD{ - Userid: "123456", - Action: 10000, - Data: inner, - } - - errs = validate.Struct(s4) - NotEqual(t, errs, nil) - Equal(t, len(errs.(ValidationErrors)), 1) - AssertError(t, errs, "ExternalCMD.Data.Name", "Name", "required") - - type TestMapStructPtr struct { - Errs map[int]interface{} `validate:"gt=0,dive,len=2"` - } - - mip := map[int]interface{}{0: &Inner{"ok"}, 3: nil, 4: &Inner{"ok"}} - - msp := &TestMapStructPtr{ - Errs: mip, - } - - errs = validate.Struct(msp) - NotEqual(t, errs, nil) - Equal(t, len(errs.(ValidationErrors)), 1) - AssertError(t, errs, "TestMapStructPtr.Errs[3]", "Errs[3]", "len") - - type TestMultiDimensionalStructs struct { - Errs [][]interface{} `validate:"gt=0,dive,dive"` - } - - var errStructArray [][]interface{} - - errStructArray = append(errStructArray, []interface{}{&Inner{"ok"}, &Inner{""}, &Inner{""}}) - errStructArray = append(errStructArray, []interface{}{&Inner{"ok"}, &Inner{""}, &Inner{""}}) - - tms := &TestMultiDimensionalStructs{ - Errs: errStructArray, - } - - errs = validate.Struct(tms) - NotEqual(t, errs, nil) - Equal(t, len(errs.(ValidationErrors)), 4) - AssertError(t, errs, "TestMultiDimensionalStructs.Errs[0][1].Name", "Name", "required") - AssertError(t, errs, "TestMultiDimensionalStructs.Errs[0][2].Name", "Name", "required") - AssertError(t, errs, "TestMultiDimensionalStructs.Errs[1][1].Name", "Name", "required") - AssertError(t, errs, "TestMultiDimensionalStructs.Errs[1][2].Name", "Name", "required") - - type TestMultiDimensionalStructsPtr2 struct { - Errs [][]*Inner `validate:"gt=0,dive,dive,required"` - } - - var errStructPtr2Array [][]*Inner - - errStructPtr2Array = append(errStructPtr2Array, []*Inner{{"ok"}, {""}, {""}}) - errStructPtr2Array = append(errStructPtr2Array, []*Inner{{"ok"}, {""}, {""}}) - errStructPtr2Array = append(errStructPtr2Array, []*Inner{{"ok"}, {""}, nil}) - - tmsp2 := &TestMultiDimensionalStructsPtr2{ - Errs: errStructPtr2Array, - } - - errs = validate.Struct(tmsp2) - NotEqual(t, errs, nil) - Equal(t, len(errs.(ValidationErrors)), 6) - AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[0][1].Name", "Name", "required") - AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[0][2].Name", "Name", "required") - AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[1][1].Name", "Name", "required") - AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[1][2].Name", "Name", "required") - AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[2][1].Name", "Name", "required") - AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[2][2]", "Errs[2][2]", "required") - - m := map[int]interface{}{0: "ok", 3: "", 4: "ok"} - - errs = validate.Field(m, "len=3,dive,len=2") - NotEqual(t, errs, nil) - Equal(t, len(errs.(ValidationErrors)), 1) - AssertError(t, errs, "[3]", "[3]", "len") - - errs = validate.Field(m, "len=2,dive,required") - NotEqual(t, errs, nil) - Equal(t, len(errs.(ValidationErrors)), 1) - AssertError(t, errs, "", "", "len") - - arr := []interface{}{"ok", "", "ok"} - - errs = validate.Field(arr, "len=3,dive,len=2") - NotEqual(t, errs, nil) - Equal(t, len(errs.(ValidationErrors)), 1) - AssertError(t, errs, "[1]", "[1]", "len") - - errs = validate.Field(arr, "len=2,dive,required") - NotEqual(t, errs, nil) - Equal(t, len(errs.(ValidationErrors)), 1) - AssertError(t, errs, "", "", "len") - - type MyStruct struct { - A, B string - C interface{} - } - - var a MyStruct - - a.A = "value" - a.C = "nu" - - errs = validate.Struct(a) - Equal(t, errs, nil) -} - -func TestMapDiveValidation(t *testing.T) { - - n := map[int]interface{}{0: nil} - errs := validate.Field(n, "omitempty,required") - Equal(t, errs, nil) - - m := map[int]string{0: "ok", 3: "", 4: "ok"} - - errs = validate.Field(m, "len=3,dive,required") - NotEqual(t, errs, nil) - Equal(t, len(errs.(ValidationErrors)), 1) - AssertError(t, errs, "[3]", "[3]", "required") - - errs = validate.Field(m, "len=2,dive,required") - NotEqual(t, errs, nil) - Equal(t, len(errs.(ValidationErrors)), 1) - AssertError(t, errs, "", "", "len") - - type Inner struct { - Name string `validate:"required"` - } - - type TestMapStruct struct { - Errs map[int]Inner `validate:"gt=0,dive"` - } - - mi := map[int]Inner{0: {"ok"}, 3: {""}, 4: {"ok"}} - - ms := &TestMapStruct{ - Errs: mi, - } - - errs = validate.Struct(ms) - NotEqual(t, errs, nil) - Equal(t, len(errs.(ValidationErrors)), 1) - AssertError(t, errs, "TestMapStruct.Errs[3].Name", "Name", "required") - - // for full test coverage - s := fmt.Sprint(errs.Error()) - NotEqual(t, s, "") - - type TestMapTimeStruct struct { - Errs map[int]*time.Time `validate:"gt=0,dive,required"` - } - - t1 := time.Now().UTC() - - mta := map[int]*time.Time{0: &t1, 3: nil, 4: nil} - - mt := &TestMapTimeStruct{ - Errs: mta, - } - - errs = validate.Struct(mt) - NotEqual(t, errs, nil) - Equal(t, len(errs.(ValidationErrors)), 2) - AssertError(t, errs, "TestMapTimeStruct.Errs[3]", "Errs[3]", "required") - AssertError(t, errs, "TestMapTimeStruct.Errs[4]", "Errs[4]", "required") - - type TestMapStructPtr struct { - Errs map[int]*Inner `validate:"gt=0,dive,required"` - } - - mip := map[int]*Inner{0: {"ok"}, 3: nil, 4: {"ok"}} - - msp := &TestMapStructPtr{ - Errs: mip, - } - - errs = validate.Struct(msp) - NotEqual(t, errs, nil) - Equal(t, len(errs.(ValidationErrors)), 1) - AssertError(t, errs, "TestMapStructPtr.Errs[3]", "Errs[3]", "required") - - type TestMapStructPtr2 struct { - Errs map[int]*Inner `validate:"gt=0,dive,omitempty,required"` - } - - mip2 := map[int]*Inner{0: {"ok"}, 3: nil, 4: {"ok"}} - - msp2 := &TestMapStructPtr2{ - Errs: mip2, - } - - errs = validate.Struct(msp2) - Equal(t, errs, nil) -} - -func TestArrayDiveValidation(t *testing.T) { - - arr := []string{"ok", "", "ok"} - - errs := validate.Field(arr, "len=3,dive,required") - NotEqual(t, errs, nil) - Equal(t, len(errs.(ValidationErrors)), 1) - AssertError(t, errs, "[1]", "[1]", "required") - - errs = validate.Field(arr, "len=2,dive,required") - NotEqual(t, errs, nil) - Equal(t, len(errs.(ValidationErrors)), 1) - AssertError(t, errs, "", "", "len") - - type BadDive struct { - Name string `validate:"dive"` - } - - bd := &BadDive{ - Name: "TEST", - } - - PanicMatches(t, func() { validate.Struct(bd) }, "dive error! can't dive on a non slice or map") - - type Test struct { - Errs []string `validate:"gt=0,dive,required"` - } - - test := &Test{ - Errs: []string{"ok", "", "ok"}, - } - - errs = validate.Struct(test) - NotEqual(t, errs, nil) - Equal(t, len(errs.(ValidationErrors)), 1) - AssertError(t, errs, "Test.Errs[1]", "Errs[1]", "required") - - test = &Test{ - Errs: []string{"ok", "ok", ""}, - } - - errs = validate.Struct(test) - NotEqual(t, errs, nil) - Equal(t, len(errs.(ValidationErrors)), 1) - AssertError(t, errs, "Test.Errs[2]", "Errs[2]", "required") - - type TestMultiDimensional struct { - Errs [][]string `validate:"gt=0,dive,dive,required"` - } - - var errArray [][]string - - errArray = append(errArray, []string{"ok", "", ""}) - errArray = append(errArray, []string{"ok", "", ""}) - - tm := &TestMultiDimensional{ - Errs: errArray, - } - - errs = validate.Struct(tm) - NotEqual(t, errs, nil) - Equal(t, len(errs.(ValidationErrors)), 4) - AssertError(t, errs, "TestMultiDimensional.Errs[0][1]", "Errs[0][1]", "required") - AssertError(t, errs, "TestMultiDimensional.Errs[0][2]", "Errs[0][2]", "required") - AssertError(t, errs, "TestMultiDimensional.Errs[1][1]", "Errs[1][1]", "required") - AssertError(t, errs, "TestMultiDimensional.Errs[1][2]", "Errs[1][2]", "required") - - type Inner struct { - Name string `validate:"required"` - } - - type TestMultiDimensionalStructs struct { - Errs [][]Inner `validate:"gt=0,dive,dive"` - } - - var errStructArray [][]Inner - - errStructArray = append(errStructArray, []Inner{{"ok"}, {""}, {""}}) - errStructArray = append(errStructArray, []Inner{{"ok"}, {""}, {""}}) - - tms := &TestMultiDimensionalStructs{ - Errs: errStructArray, - } - - errs = validate.Struct(tms) - NotEqual(t, errs, nil) - Equal(t, len(errs.(ValidationErrors)), 4) - AssertError(t, errs, "TestMultiDimensionalStructs.Errs[0][1].Name", "Name", "required") - AssertError(t, errs, "TestMultiDimensionalStructs.Errs[0][2].Name", "Name", "required") - AssertError(t, errs, "TestMultiDimensionalStructs.Errs[1][1].Name", "Name", "required") - AssertError(t, errs, "TestMultiDimensionalStructs.Errs[1][2].Name", "Name", "required") - - type TestMultiDimensionalStructsPtr struct { - Errs [][]*Inner `validate:"gt=0,dive,dive"` - } - - var errStructPtrArray [][]*Inner - - errStructPtrArray = append(errStructPtrArray, []*Inner{{"ok"}, {""}, {""}}) - errStructPtrArray = append(errStructPtrArray, []*Inner{{"ok"}, {""}, {""}}) - errStructPtrArray = append(errStructPtrArray, []*Inner{{"ok"}, {""}, nil}) - - tmsp := &TestMultiDimensionalStructsPtr{ - Errs: errStructPtrArray, - } - - errs = validate.Struct(tmsp) - NotEqual(t, errs, nil) - Equal(t, len(errs.(ValidationErrors)), 5) - AssertError(t, errs, "TestMultiDimensionalStructsPtr.Errs[0][1].Name", "Name", "required") - AssertError(t, errs, "TestMultiDimensionalStructsPtr.Errs[0][2].Name", "Name", "required") - AssertError(t, errs, "TestMultiDimensionalStructsPtr.Errs[1][1].Name", "Name", "required") - AssertError(t, errs, "TestMultiDimensionalStructsPtr.Errs[1][2].Name", "Name", "required") - AssertError(t, errs, "TestMultiDimensionalStructsPtr.Errs[2][1].Name", "Name", "required") - - // for full test coverage - s := fmt.Sprint(errs.Error()) - NotEqual(t, s, "") - - type TestMultiDimensionalStructsPtr2 struct { - Errs [][]*Inner `validate:"gt=0,dive,dive,required"` - } - - var errStructPtr2Array [][]*Inner - - errStructPtr2Array = append(errStructPtr2Array, []*Inner{{"ok"}, {""}, {""}}) - errStructPtr2Array = append(errStructPtr2Array, []*Inner{{"ok"}, {""}, {""}}) - errStructPtr2Array = append(errStructPtr2Array, []*Inner{{"ok"}, {""}, nil}) - - tmsp2 := &TestMultiDimensionalStructsPtr2{ - Errs: errStructPtr2Array, - } - - errs = validate.Struct(tmsp2) - NotEqual(t, errs, nil) - Equal(t, len(errs.(ValidationErrors)), 6) - AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[0][1].Name", "Name", "required") - AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[0][2].Name", "Name", "required") - AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[1][1].Name", "Name", "required") - AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[1][2].Name", "Name", "required") - AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[2][1].Name", "Name", "required") - AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[2][2]", "Errs[2][2]", "required") - - type TestMultiDimensionalStructsPtr3 struct { - Errs [][]*Inner `validate:"gt=0,dive,dive,omitempty"` - } - - var errStructPtr3Array [][]*Inner - - errStructPtr3Array = append(errStructPtr3Array, []*Inner{{"ok"}, {""}, {""}}) - errStructPtr3Array = append(errStructPtr3Array, []*Inner{{"ok"}, {""}, {""}}) - errStructPtr3Array = append(errStructPtr3Array, []*Inner{{"ok"}, {""}, nil}) - - tmsp3 := &TestMultiDimensionalStructsPtr3{ - Errs: errStructPtr3Array, - } - - errs = validate.Struct(tmsp3) - NotEqual(t, errs, nil) - Equal(t, len(errs.(ValidationErrors)), 5) - AssertError(t, errs, "TestMultiDimensionalStructsPtr3.Errs[0][1].Name", "Name", "required") - AssertError(t, errs, "TestMultiDimensionalStructsPtr3.Errs[0][2].Name", "Name", "required") - AssertError(t, errs, "TestMultiDimensionalStructsPtr3.Errs[1][1].Name", "Name", "required") - AssertError(t, errs, "TestMultiDimensionalStructsPtr3.Errs[1][2].Name", "Name", "required") - AssertError(t, errs, "TestMultiDimensionalStructsPtr3.Errs[2][1].Name", "Name", "required") - - type TestMultiDimensionalTimeTime struct { - Errs [][]*time.Time `validate:"gt=0,dive,dive,required"` - } - - var errTimePtr3Array [][]*time.Time - - t1 := time.Now().UTC() - t2 := time.Now().UTC() - t3 := time.Now().UTC().Add(time.Hour * 24) - - errTimePtr3Array = append(errTimePtr3Array, []*time.Time{&t1, &t2, &t3}) - errTimePtr3Array = append(errTimePtr3Array, []*time.Time{&t1, &t2, nil}) - errTimePtr3Array = append(errTimePtr3Array, []*time.Time{&t1, nil, nil}) - - tmtp3 := &TestMultiDimensionalTimeTime{ - Errs: errTimePtr3Array, - } - - errs = validate.Struct(tmtp3) - NotEqual(t, errs, nil) - Equal(t, len(errs.(ValidationErrors)), 3) - AssertError(t, errs, "TestMultiDimensionalTimeTime.Errs[1][2]", "Errs[1][2]", "required") - AssertError(t, errs, "TestMultiDimensionalTimeTime.Errs[2][1]", "Errs[2][1]", "required") - AssertError(t, errs, "TestMultiDimensionalTimeTime.Errs[2][2]", "Errs[2][2]", "required") - - type TestMultiDimensionalTimeTime2 struct { - Errs [][]*time.Time `validate:"gt=0,dive,dive,required"` - } - - var errTimeArray [][]*time.Time - - t1 = time.Now().UTC() - t2 = time.Now().UTC() - t3 = time.Now().UTC().Add(time.Hour * 24) - - errTimeArray = append(errTimeArray, []*time.Time{&t1, &t2, &t3}) - errTimeArray = append(errTimeArray, []*time.Time{&t1, &t2, nil}) - errTimeArray = append(errTimeArray, []*time.Time{&t1, nil, nil}) - - tmtp := &TestMultiDimensionalTimeTime2{ - Errs: errTimeArray, - } - - errs = validate.Struct(tmtp) - NotEqual(t, errs, nil) - Equal(t, len(errs.(ValidationErrors)), 3) - AssertError(t, errs, "TestMultiDimensionalTimeTime2.Errs[1][2]", "Errs[1][2]", "required") - AssertError(t, errs, "TestMultiDimensionalTimeTime2.Errs[2][1]", "Errs[2][1]", "required") - AssertError(t, errs, "TestMultiDimensionalTimeTime2.Errs[2][2]", "Errs[2][2]", "required") -} - -func TestNilStructPointerValidation(t *testing.T) { - type Inner struct { - Data string - } - - type Outer struct { - Inner *Inner `validate:"omitempty"` - } - - inner := &Inner{ - Data: "test", - } - - outer := &Outer{ - Inner: inner, - } - - errs := validate.Struct(outer) - Equal(t, errs, nil) - - outer = &Outer{ - Inner: nil, - } - - errs = validate.Struct(outer) - Equal(t, errs, nil) - - type Inner2 struct { - Data string - } - - type Outer2 struct { - Inner2 *Inner2 `validate:"required"` - } - - inner2 := &Inner2{ - Data: "test", - } - - outer2 := &Outer2{ - Inner2: inner2, - } - - errs = validate.Struct(outer2) - Equal(t, errs, nil) - - outer2 = &Outer2{ - Inner2: nil, - } - - errs = validate.Struct(outer2) - NotEqual(t, errs, nil) - AssertError(t, errs, "Outer2.Inner2", "Inner2", "required") - - type Inner3 struct { - Data string - } - - type Outer3 struct { - Inner3 *Inner3 - } - - inner3 := &Inner3{ - Data: "test", - } - - outer3 := &Outer3{ - Inner3: inner3, - } - - errs = validate.Struct(outer3) - Equal(t, errs, nil) - - type Inner4 struct { - Data string - } - - type Outer4 struct { - Inner4 *Inner4 `validate:"-"` - } - - inner4 := &Inner4{ - Data: "test", - } - - outer4 := &Outer4{ - Inner4: inner4, - } - - errs = validate.Struct(outer4) - Equal(t, errs, nil) -} - -func TestSSNValidation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"", false}, - {"00-90-8787", false}, - {"66690-76", false}, - {"191 60 2869", true}, - {"191-60-2869", true}, - } - - for i, test := range tests { - - errs := validate.Field(test.param, "ssn") - - if test.expected { - if !IsEqual(errs, nil) { - t.Fatalf("Index: %d SSN failed Error: %s", i, errs) - } - } else { - if IsEqual(errs, nil) { - t.Fatalf("Index: %d SSN failed Error: %s", i, errs) - } else { - val := errs.(ValidationErrors)[""] - if val.Tag != "ssn" { - t.Fatalf("Index: %d Latitude failed Error: %s", i, errs) - } - } - } - } -} - -func TestLongitudeValidation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"", false}, - {"-180.000", true}, - {"180.1", false}, - {"+73.234", true}, - {"+382.3811", false}, - {"23.11111111", true}, - } - - for i, test := range tests { - - errs := validate.Field(test.param, "longitude") - - if test.expected { - if !IsEqual(errs, nil) { - t.Fatalf("Index: %d Longitude failed Error: %s", i, errs) - } - } else { - if IsEqual(errs, nil) { - t.Fatalf("Index: %d Longitude failed Error: %s", i, errs) - } else { - val := errs.(ValidationErrors)[""] - if val.Tag != "longitude" { - t.Fatalf("Index: %d Latitude failed Error: %s", i, errs) - } - } - } - } -} - -func TestLatitudeValidation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"", false}, - {"-90.000", true}, - {"+90", true}, - {"47.1231231", true}, - {"+99.9", false}, - {"108", false}, - } - - for i, test := range tests { - - errs := validate.Field(test.param, "latitude") - - if test.expected { - if !IsEqual(errs, nil) { - t.Fatalf("Index: %d Latitude failed Error: %s", i, errs) - } - } else { - if IsEqual(errs, nil) { - t.Fatalf("Index: %d Latitude failed Error: %s", i, errs) - } else { - val := errs.(ValidationErrors)[""] - if val.Tag != "latitude" { - t.Fatalf("Index: %d Latitude failed Error: %s", i, errs) - } - } - } - } -} - -func TestDataURIValidation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"data:image/png;base64,TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4=", true}, - {"data:text/plain;base64,Vml2YW11cyBmZXJtZW50dW0gc2VtcGVyIHBvcnRhLg==", true}, - {"image/gif;base64,U3VzcGVuZGlzc2UgbGVjdHVzIGxlbw==", false}, - {"data:image/gif;base64,MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuMPNS1Ufof9EW/M98FNw" + - "UAKrwflsqVxaxQjBQnHQmiI7Vac40t8x7pIb8gLGV6wL7sBTJiPovJ0V7y7oc0Ye" + - "rhKh0Rm4skP2z/jHwwZICgGzBvA0rH8xlhUiTvcwDCJ0kc+fh35hNt8srZQM4619" + - "FTgB66Xmp4EtVyhpQV+t02g6NzK72oZI0vnAvqhpkxLeLiMCyrI416wHm5Tkukhx" + - "QmcL2a6hNOyu0ixX/x2kSFXApEnVrJ+/IxGyfyw8kf4N2IZpW5nEP847lpfj0SZZ" + - "Fwrd1mnfnDbYohX2zRptLy2ZUn06Qo9pkG5ntvFEPo9bfZeULtjYzIl6K8gJ2uGZ" + "HQIDAQAB", true}, - {"data:image/png;base64,12345", false}, - {"", false}, - {"data:text,:;base85,U3VzcGVuZGlzc2UgbGVjdHVzIGxlbw==", false}, - } - - for i, test := range tests { - - errs := validate.Field(test.param, "datauri") - - if test.expected { - if !IsEqual(errs, nil) { - t.Fatalf("Index: %d DataURI failed Error: %s", i, errs) - } - } else { - if IsEqual(errs, nil) { - t.Fatalf("Index: %d DataURI failed Error: %s", i, errs) - } else { - val := errs.(ValidationErrors)[""] - if val.Tag != "datauri" { - t.Fatalf("Index: %d DataURI failed Error: %s", i, errs) - } - } - } - } -} - -func TestMultibyteValidation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"", true}, - {"abc", false}, - {"123", false}, - {"<>@;.-=", false}, - {"ひらがな・カタカナ、.漢字", true}, - {"あいうえお foobar", true}, - {"test@example.com", true}, - {"test@example.com", true}, - {"1234abcDExyz", true}, - {"カタカナ", true}, - } - - for i, test := range tests { - - errs := validate.Field(test.param, "multibyte") - - if test.expected { - if !IsEqual(errs, nil) { - t.Fatalf("Index: %d Multibyte failed Error: %s", i, errs) - } - } else { - if IsEqual(errs, nil) { - t.Fatalf("Index: %d Multibyte failed Error: %s", i, errs) - } else { - val := errs.(ValidationErrors)[""] - if val.Tag != "multibyte" { - t.Fatalf("Index: %d Multibyte failed Error: %s", i, errs) - } - } - } - } -} - -func TestPrintableASCIIValidation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"", true}, - {"foobar", false}, - {"xyz098", false}, - {"123456", false}, - {"カタカナ", false}, - {"foobar", true}, - {"0987654321", true}, - {"test@example.com", true}, - {"1234abcDEF", true}, - {"newline\n", false}, - {"\x19test\x7F", false}, - } - - for i, test := range tests { - - errs := validate.Field(test.param, "printascii") - - if test.expected { - if !IsEqual(errs, nil) { - t.Fatalf("Index: %d Printable ASCII failed Error: %s", i, errs) - } - } else { - if IsEqual(errs, nil) { - t.Fatalf("Index: %d Printable ASCII failed Error: %s", i, errs) - } else { - val := errs.(ValidationErrors)[""] - if val.Tag != "printascii" { - t.Fatalf("Index: %d Printable ASCII failed Error: %s", i, errs) - } - } - } - } -} - -func TestASCIIValidation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"", true}, - {"foobar", false}, - {"xyz098", false}, - {"123456", false}, - {"カタカナ", false}, - {"foobar", true}, - {"0987654321", true}, - {"test@example.com", true}, - {"1234abcDEF", true}, - {"", true}, - } - - for i, test := range tests { - - errs := validate.Field(test.param, "ascii") - - if test.expected { - if !IsEqual(errs, nil) { - t.Fatalf("Index: %d ASCII failed Error: %s", i, errs) - } - } else { - if IsEqual(errs, nil) { - t.Fatalf("Index: %d ASCII failed Error: %s", i, errs) - } else { - val := errs.(ValidationErrors)[""] - if val.Tag != "ascii" { - t.Fatalf("Index: %d ASCII failed Error: %s", i, errs) - } - } - } - } -} - -func TestUUID5Validation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - - {"", false}, - {"xxxa987fbc9-4bed-3078-cf07-9141ba07c9f3", false}, - {"9c858901-8a57-4791-81fe-4c455b099bc9", false}, - {"a987fbc9-4bed-3078-cf07-9141ba07c9f3", false}, - {"987fbc97-4bed-5078-af07-9141ba07c9f3", true}, - {"987fbc97-4bed-5078-9f07-9141ba07c9f3", true}, - } - - for i, test := range tests { - - errs := validate.Field(test.param, "uuid5") - - if test.expected { - if !IsEqual(errs, nil) { - t.Fatalf("Index: %d UUID5 failed Error: %s", i, errs) - } - } else { - if IsEqual(errs, nil) { - t.Fatalf("Index: %d UUID5 failed Error: %s", i, errs) - } else { - val := errs.(ValidationErrors)[""] - if val.Tag != "uuid5" { - t.Fatalf("Index: %d UUID5 failed Error: %s", i, errs) - } - } - } - } -} - -func TestUUID4Validation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"", false}, - {"xxxa987fbc9-4bed-3078-cf07-9141ba07c9f3", false}, - {"a987fbc9-4bed-5078-af07-9141ba07c9f3", false}, - {"934859", false}, - {"57b73598-8764-4ad0-a76a-679bb6640eb1", true}, - {"625e63f3-58f5-40b7-83a1-a72ad31acffb", true}, - } - - for i, test := range tests { - - errs := validate.Field(test.param, "uuid4") - - if test.expected { - if !IsEqual(errs, nil) { - t.Fatalf("Index: %d UUID4 failed Error: %s", i, errs) - } - } else { - if IsEqual(errs, nil) { - t.Fatalf("Index: %d UUID4 failed Error: %s", i, errs) - } else { - val := errs.(ValidationErrors)[""] - if val.Tag != "uuid4" { - t.Fatalf("Index: %d UUID4 failed Error: %s", i, errs) - } - } - } - } -} - -func TestUUID3Validation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"", false}, - {"412452646", false}, - {"xxxa987fbc9-4bed-3078-cf07-9141ba07c9f3", false}, - {"a987fbc9-4bed-4078-8f07-9141ba07c9f3", false}, - {"a987fbc9-4bed-3078-cf07-9141ba07c9f3", true}, - } - - for i, test := range tests { - - errs := validate.Field(test.param, "uuid3") - - if test.expected { - if !IsEqual(errs, nil) { - t.Fatalf("Index: %d UUID3 failed Error: %s", i, errs) - } - } else { - if IsEqual(errs, nil) { - t.Fatalf("Index: %d UUID3 failed Error: %s", i, errs) - } else { - val := errs.(ValidationErrors)[""] - if val.Tag != "uuid3" { - t.Fatalf("Index: %d UUID3 failed Error: %s", i, errs) - } - } - } - } -} - -func TestUUIDValidation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"", false}, - {"xxxa987fbc9-4bed-3078-cf07-9141ba07c9f3", false}, - {"a987fbc9-4bed-3078-cf07-9141ba07c9f3xxx", false}, - {"a987fbc94bed3078cf079141ba07c9f3", false}, - {"934859", false}, - {"987fbc9-4bed-3078-cf07a-9141ba07c9f3", false}, - {"aaaaaaaa-1111-1111-aaag-111111111111", false}, - {"a987fbc9-4bed-3078-cf07-9141ba07c9f3", true}, - } - - for i, test := range tests { - - errs := validate.Field(test.param, "uuid") - - if test.expected { - if !IsEqual(errs, nil) { - t.Fatalf("Index: %d UUID failed Error: %s", i, errs) - } - } else { - if IsEqual(errs, nil) { - t.Fatalf("Index: %d UUID failed Error: %s", i, errs) - } else { - val := errs.(ValidationErrors)[""] - if val.Tag != "uuid" { - t.Fatalf("Index: %d UUID failed Error: %s", i, errs) - } - } - } - } -} - -func TestISBNValidation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"", false}, - {"foo", false}, - {"3836221195", true}, - {"1-61729-085-8", true}, - {"3 423 21412 0", true}, - {"3 401 01319 X", true}, - {"9784873113685", true}, - {"978-4-87311-368-5", true}, - {"978 3401013190", true}, - {"978-3-8362-2119-1", true}, - } - - for i, test := range tests { - - errs := validate.Field(test.param, "isbn") - - if test.expected { - if !IsEqual(errs, nil) { - t.Fatalf("Index: %d ISBN failed Error: %s", i, errs) - } - } else { - if IsEqual(errs, nil) { - t.Fatalf("Index: %d ISBN failed Error: %s", i, errs) - } else { - val := errs.(ValidationErrors)[""] - if val.Tag != "isbn" { - t.Fatalf("Index: %d ISBN failed Error: %s", i, errs) - } - } - } - } -} - -func TestISBN13Validation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"", false}, - {"foo", false}, - {"3-8362-2119-5", false}, - {"01234567890ab", false}, - {"978 3 8362 2119 0", false}, - {"9784873113685", true}, - {"978-4-87311-368-5", true}, - {"978 3401013190", true}, - {"978-3-8362-2119-1", true}, - } - - for i, test := range tests { - - errs := validate.Field(test.param, "isbn13") - - if test.expected { - if !IsEqual(errs, nil) { - t.Fatalf("Index: %d ISBN13 failed Error: %s", i, errs) - } - } else { - if IsEqual(errs, nil) { - t.Fatalf("Index: %d ISBN13 failed Error: %s", i, errs) - } else { - val := errs.(ValidationErrors)[""] - if val.Tag != "isbn13" { - t.Fatalf("Index: %d ISBN13 failed Error: %s", i, errs) - } - } - } - } -} - -func TestISBN10Validation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"", false}, - {"foo", false}, - {"3423214121", false}, - {"978-3836221191", false}, - {"3-423-21412-1", false}, - {"3 423 21412 1", false}, - {"3836221195", true}, - {"1-61729-085-8", true}, - {"3 423 21412 0", true}, - {"3 401 01319 X", true}, - } - - for i, test := range tests { - - errs := validate.Field(test.param, "isbn10") - - if test.expected { - if !IsEqual(errs, nil) { - t.Fatalf("Index: %d ISBN10 failed Error: %s", i, errs) - } - } else { - if IsEqual(errs, nil) { - t.Fatalf("Index: %d ISBN10 failed Error: %s", i, errs) - } else { - val := errs.(ValidationErrors)[""] - if val.Tag != "isbn10" { - t.Fatalf("Index: %d ISBN10 failed Error: %s", i, errs) - } - } - } - } -} - -func TestExcludesRuneValidation(t *testing.T) { - - tests := []struct { - Value string `validate:"excludesrune=☻"` - Tag string - ExpectedNil bool - }{ - {Value: "a☺b☻c☹d", Tag: "excludesrune=☻", ExpectedNil: false}, - {Value: "abcd", Tag: "excludesrune=☻", ExpectedNil: true}, - } - - for i, s := range tests { - errs := validate.Field(s.Value, s.Tag) - - if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { - t.Fatalf("Index: %d failed Error: %s", i, errs) - } - - errs = validate.Struct(s) - - if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { - t.Fatalf("Index: %d failed Error: %s", i, errs) - } - } -} - -func TestExcludesAllValidation(t *testing.T) { - - tests := []struct { - Value string `validate:"excludesall=@!{}[]"` - Tag string - ExpectedNil bool - }{ - {Value: "abcd@!jfk", Tag: "excludesall=@!{}[]", ExpectedNil: false}, - {Value: "abcdefg", Tag: "excludesall=@!{}[]", ExpectedNil: true}, - } - - for i, s := range tests { - errs := validate.Field(s.Value, s.Tag) - - if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { - t.Fatalf("Index: %d failed Error: %s", i, errs) - } - - errs = validate.Struct(s) - - if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { - t.Fatalf("Index: %d failed Error: %s", i, errs) - } - } - - username := "joeybloggs " - - errs := validate.Field(username, "excludesall=@ ") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "excludesall") - - excluded := "," - - errs = validate.Field(excluded, "excludesall=!@#$%^&*()_+.0x2C?") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "excludesall") - - excluded = "=" - - errs = validate.Field(excluded, "excludesall=!@#$%^&*()_+.0x2C=?") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "excludesall") -} - -func TestExcludesValidation(t *testing.T) { - - tests := []struct { - Value string `validate:"excludes=@"` - Tag string - ExpectedNil bool - }{ - {Value: "abcd@!jfk", Tag: "excludes=@", ExpectedNil: false}, - {Value: "abcdq!jfk", Tag: "excludes=@", ExpectedNil: true}, - } - - for i, s := range tests { - errs := validate.Field(s.Value, s.Tag) - - if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { - t.Fatalf("Index: %d failed Error: %s", i, errs) - } - - errs = validate.Struct(s) - - if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { - t.Fatalf("Index: %d failed Error: %s", i, errs) - } - } -} - -func TestContainsRuneValidation(t *testing.T) { - - tests := []struct { - Value string `validate:"containsrune=☻"` - Tag string - ExpectedNil bool - }{ - {Value: "a☺b☻c☹d", Tag: "containsrune=☻", ExpectedNil: true}, - {Value: "abcd", Tag: "containsrune=☻", ExpectedNil: false}, - } - - for i, s := range tests { - errs := validate.Field(s.Value, s.Tag) - - if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { - t.Fatalf("Index: %d failed Error: %s", i, errs) - } - - errs = validate.Struct(s) - - if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { - t.Fatalf("Index: %d failed Error: %s", i, errs) - } - } -} - -func TestContainsAnyValidation(t *testing.T) { - - tests := []struct { - Value string `validate:"containsany=@!{}[]"` - Tag string - ExpectedNil bool - }{ - {Value: "abcd@!jfk", Tag: "containsany=@!{}[]", ExpectedNil: true}, - {Value: "abcdefg", Tag: "containsany=@!{}[]", ExpectedNil: false}, - } - - for i, s := range tests { - errs := validate.Field(s.Value, s.Tag) - - if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { - t.Fatalf("Index: %d failed Error: %s", i, errs) - } - - errs = validate.Struct(s) - - if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { - t.Fatalf("Index: %d failed Error: %s", i, errs) - } - } -} - -func TestContainsValidation(t *testing.T) { - - tests := []struct { - Value string `validate:"contains=@"` - Tag string - ExpectedNil bool - }{ - {Value: "abcd@!jfk", Tag: "contains=@", ExpectedNil: true}, - {Value: "abcdq!jfk", Tag: "contains=@", ExpectedNil: false}, - } - - for i, s := range tests { - errs := validate.Field(s.Value, s.Tag) - - if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { - t.Fatalf("Index: %d failed Error: %s", i, errs) - } - - errs = validate.Struct(s) - - if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { - t.Fatalf("Index: %d failed Error: %s", i, errs) - } - } -} - -func TestIsNeFieldValidation(t *testing.T) { - - var j uint64 - var k float64 - s := "abcd" - i := 1 - j = 1 - k = 1.543 - arr := []string{"test"} - now := time.Now().UTC() - - var j2 uint64 - var k2 float64 - s2 := "abcdef" - i2 := 3 - j2 = 2 - k2 = 1.5434456 - arr2 := []string{"test", "test2"} - arr3 := []string{"test"} - now2 := now - - errs := validate.FieldWithValue(s, s2, "nefield") - Equal(t, errs, nil) - - errs = validate.FieldWithValue(i2, i, "nefield") - Equal(t, errs, nil) - - errs = validate.FieldWithValue(j2, j, "nefield") - Equal(t, errs, nil) - - errs = validate.FieldWithValue(k2, k, "nefield") - Equal(t, errs, nil) - - errs = validate.FieldWithValue(arr2, arr, "nefield") - Equal(t, errs, nil) - - errs = validate.FieldWithValue(now2, now, "nefield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "nefield") - - errs = validate.FieldWithValue(arr3, arr, "nefield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "nefield") - - type Test struct { - Start *time.Time `validate:"nefield=End"` - End *time.Time - } - - sv := &Test{ - Start: &now, - End: &now, - } - - errs = validate.Struct(sv) - NotEqual(t, errs, nil) - AssertError(t, errs, "Test.Start", "Start", "nefield") - - now3 := time.Now().UTC() - - sv = &Test{ - Start: &now, - End: &now3, - } - - errs = validate.Struct(sv) - Equal(t, errs, nil) - - errs = validate.FieldWithValue(nil, 1, "nefield") - Equal(t, errs, nil) - - errs = validate.FieldWithValue(sv, now, "nefield") - Equal(t, errs, nil) - - type Test2 struct { - Start *time.Time `validate:"nefield=NonExistantField"` - End *time.Time - } - - sv2 := &Test2{ - Start: &now, - End: &now, - } - - errs = validate.Struct(sv2) - Equal(t, errs, nil) -} - -func TestIsNeValidation(t *testing.T) { - - var j uint64 - var k float64 - s := "abcdef" - i := 3 - j = 2 - k = 1.5434 - arr := []string{"test"} - now := time.Now().UTC() - - errs := validate.Field(s, "ne=abcd") - Equal(t, errs, nil) - - errs = validate.Field(i, "ne=1") - Equal(t, errs, nil) - - errs = validate.Field(j, "ne=1") - Equal(t, errs, nil) - - errs = validate.Field(k, "ne=1.543") - Equal(t, errs, nil) - - errs = validate.Field(arr, "ne=2") - Equal(t, errs, nil) - - errs = validate.Field(arr, "ne=1") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "ne") - - PanicMatches(t, func() { validate.Field(now, "ne=now") }, "Bad field type time.Time") -} - -func TestIsEqFieldValidation(t *testing.T) { - - var j uint64 - var k float64 - s := "abcd" - i := 1 - j = 1 - k = 1.543 - arr := []string{"test"} - now := time.Now().UTC() - - var j2 uint64 - var k2 float64 - s2 := "abcd" - i2 := 1 - j2 = 1 - k2 = 1.543 - arr2 := []string{"test"} - arr3 := []string{"test", "test2"} - now2 := now - - errs := validate.FieldWithValue(s, s2, "eqfield") - Equal(t, errs, nil) - - errs = validate.FieldWithValue(i2, i, "eqfield") - Equal(t, errs, nil) - - errs = validate.FieldWithValue(j2, j, "eqfield") - Equal(t, errs, nil) - - errs = validate.FieldWithValue(k2, k, "eqfield") - Equal(t, errs, nil) - - errs = validate.FieldWithValue(arr2, arr, "eqfield") - Equal(t, errs, nil) - - errs = validate.FieldWithValue(now2, now, "eqfield") - Equal(t, errs, nil) - - errs = validate.FieldWithValue(arr3, arr, "eqfield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "eqfield") - - type Test struct { - Start *time.Time `validate:"eqfield=End"` - End *time.Time - } - - sv := &Test{ - Start: &now, - End: &now, - } - - errs = validate.Struct(sv) - Equal(t, errs, nil) - - now3 := time.Now().UTC() - - sv = &Test{ - Start: &now, - End: &now3, - } - - errs = validate.Struct(sv) - NotEqual(t, errs, nil) - AssertError(t, errs, "Test.Start", "Start", "eqfield") - - errs = validate.FieldWithValue(nil, 1, "eqfield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "eqfield") - - channel := make(chan string) - errs = validate.FieldWithValue(5, channel, "eqfield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "eqfield") - - errs = validate.FieldWithValue(5, now, "eqfield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "eqfield") - - type Test2 struct { - Start *time.Time `validate:"eqfield=NonExistantField"` - End *time.Time - } - - sv2 := &Test2{ - Start: &now, - End: &now, - } - - errs = validate.Struct(sv2) - NotEqual(t, errs, nil) - AssertError(t, errs, "Test2.Start", "Start", "eqfield") - - type Inner struct { - Name string - } - - type TStruct struct { - Inner *Inner - CreatedAt *time.Time `validate:"eqfield=Inner"` - } - - inner := &Inner{ - Name: "NAME", - } - - test := &TStruct{ - Inner: inner, - CreatedAt: &now, - } - - errs = validate.Struct(test) - NotEqual(t, errs, nil) - AssertError(t, errs, "TStruct.CreatedAt", "CreatedAt", "eqfield") -} - -func TestIsEqValidation(t *testing.T) { - - var j uint64 - var k float64 - s := "abcd" - i := 1 - j = 1 - k = 1.543 - arr := []string{"test"} - now := time.Now().UTC() - - errs := validate.Field(s, "eq=abcd") - Equal(t, errs, nil) - - errs = validate.Field(i, "eq=1") - Equal(t, errs, nil) - - errs = validate.Field(j, "eq=1") - Equal(t, errs, nil) - - errs = validate.Field(k, "eq=1.543") - Equal(t, errs, nil) - - errs = validate.Field(arr, "eq=1") - Equal(t, errs, nil) - - errs = validate.Field(arr, "eq=2") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "eq") - - PanicMatches(t, func() { validate.Field(now, "eq=now") }, "Bad field type time.Time") -} - -func TestBase64Validation(t *testing.T) { - - s := "dW5pY29ybg==" - - errs := validate.Field(s, "base64") - Equal(t, errs, nil) - - s = "dGhpIGlzIGEgdGVzdCBiYXNlNjQ=" - errs = validate.Field(s, "base64") - Equal(t, errs, nil) - - s = "" - errs = validate.Field(s, "base64") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "base64") - - s = "dW5pY29ybg== foo bar" - errs = validate.Field(s, "base64") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "base64") -} - -func TestNoStructLevelValidation(t *testing.T) { - - type Inner struct { - Test string `validate:"len=5"` - } - - type Outer struct { - InnerStruct *Inner `validate:"required,nostructlevel"` - } - - outer := &Outer{ - InnerStruct: nil, - } - - errs := validate.Struct(outer) - NotEqual(t, errs, nil) - AssertError(t, errs, "Outer.InnerStruct", "InnerStruct", "required") - - inner := &Inner{ - Test: "1234", - } - - outer = &Outer{ - InnerStruct: inner, - } - - errs = validate.Struct(outer) - Equal(t, errs, nil) -} - -func TestStructOnlyValidation(t *testing.T) { - - type Inner struct { - Test string `validate:"len=5"` - } - - type Outer struct { - InnerStruct *Inner `validate:"required,structonly"` - } - - outer := &Outer{ - InnerStruct: nil, - } - - errs := validate.Struct(outer) - NotEqual(t, errs, nil) - AssertError(t, errs, "Outer.InnerStruct", "InnerStruct", "required") - - inner := &Inner{ - Test: "1234", - } - - outer = &Outer{ - InnerStruct: inner, - } - - errs = validate.Struct(outer) - Equal(t, errs, nil) -} - -func TestGtField(t *testing.T) { - - type TimeTest struct { - Start *time.Time `validate:"required,gt"` - End *time.Time `validate:"required,gt,gtfield=Start"` - } - - now := time.Now() - start := now.Add(time.Hour * 24) - end := start.Add(time.Hour * 24) - - timeTest := &TimeTest{ - Start: &start, - End: &end, - } - - errs := validate.Struct(timeTest) - Equal(t, errs, nil) - - timeTest = &TimeTest{ - Start: &end, - End: &start, - } - - errs = validate.Struct(timeTest) - NotEqual(t, errs, nil) - AssertError(t, errs, "TimeTest.End", "End", "gtfield") - - errs = validate.FieldWithValue(&start, &end, "gtfield") - Equal(t, errs, nil) - - errs = validate.FieldWithValue(&end, &start, "gtfield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "gtfield") - - errs = validate.FieldWithValue(&timeTest, &end, "gtfield") - NotEqual(t, errs, nil) - - errs = validate.FieldWithValue("test", "test bigger", "gtfield") - Equal(t, errs, nil) - - type IntTest struct { - Val1 int `validate:"required"` - Val2 int `validate:"required,gtfield=Val1"` - } - - intTest := &IntTest{ - Val1: 1, - Val2: 5, - } - - errs = validate.Struct(intTest) - Equal(t, errs, nil) - - intTest = &IntTest{ - Val1: 5, - Val2: 1, - } - - errs = validate.Struct(intTest) - NotEqual(t, errs, nil) - AssertError(t, errs, "IntTest.Val2", "Val2", "gtfield") - - errs = validate.FieldWithValue(int(1), int(5), "gtfield") - Equal(t, errs, nil) - - errs = validate.FieldWithValue(int(5), int(1), "gtfield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "gtfield") - - type UIntTest struct { - Val1 uint `validate:"required"` - Val2 uint `validate:"required,gtfield=Val1"` - } - - uIntTest := &UIntTest{ - Val1: 1, - Val2: 5, - } - - errs = validate.Struct(uIntTest) - Equal(t, errs, nil) - - uIntTest = &UIntTest{ - Val1: 5, - Val2: 1, - } - - errs = validate.Struct(uIntTest) - NotEqual(t, errs, nil) - AssertError(t, errs, "UIntTest.Val2", "Val2", "gtfield") - - errs = validate.FieldWithValue(uint(1), uint(5), "gtfield") - Equal(t, errs, nil) - - errs = validate.FieldWithValue(uint(5), uint(1), "gtfield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "gtfield") - - type FloatTest struct { - Val1 float64 `validate:"required"` - Val2 float64 `validate:"required,gtfield=Val1"` - } - - floatTest := &FloatTest{ - Val1: 1, - Val2: 5, - } - - errs = validate.Struct(floatTest) - Equal(t, errs, nil) - - floatTest = &FloatTest{ - Val1: 5, - Val2: 1, - } - - errs = validate.Struct(floatTest) - NotEqual(t, errs, nil) - AssertError(t, errs, "FloatTest.Val2", "Val2", "gtfield") - - errs = validate.FieldWithValue(float32(1), float32(5), "gtfield") - Equal(t, errs, nil) - - errs = validate.FieldWithValue(float32(5), float32(1), "gtfield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "gtfield") - - errs = validate.FieldWithValue(nil, 1, "gtfield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "gtfield") - - errs = validate.FieldWithValue(5, "T", "gtfield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "gtfield") - - errs = validate.FieldWithValue(5, start, "gtfield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "gtfield") - - type TimeTest2 struct { - Start *time.Time `validate:"required"` - End *time.Time `validate:"required,gtfield=NonExistantField"` - } - - timeTest2 := &TimeTest2{ - Start: &start, - End: &end, - } - - errs = validate.Struct(timeTest2) - NotEqual(t, errs, nil) - AssertError(t, errs, "TimeTest2.End", "End", "gtfield") -} - -func TestLtField(t *testing.T) { - - type TimeTest struct { - Start *time.Time `validate:"required,lt,ltfield=End"` - End *time.Time `validate:"required,lt"` - } - - now := time.Now() - start := now.Add(time.Hour * 24 * -1 * 2) - end := start.Add(time.Hour * 24) - - timeTest := &TimeTest{ - Start: &start, - End: &end, - } - - errs := validate.Struct(timeTest) - Equal(t, errs, nil) - - timeTest = &TimeTest{ - Start: &end, - End: &start, - } - - errs = validate.Struct(timeTest) - NotEqual(t, errs, nil) - AssertError(t, errs, "TimeTest.Start", "Start", "ltfield") - - errs = validate.FieldWithValue(&end, &start, "ltfield") - Equal(t, errs, nil) - - errs = validate.FieldWithValue(&start, &end, "ltfield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "ltfield") - - errs = validate.FieldWithValue(timeTest, &end, "ltfield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "ltfield") - - errs = validate.FieldWithValue("test", "tes", "ltfield") - Equal(t, errs, nil) - - type IntTest struct { - Val1 int `validate:"required"` - Val2 int `validate:"required,ltfield=Val1"` - } - - intTest := &IntTest{ - Val1: 5, - Val2: 1, - } - - errs = validate.Struct(intTest) - Equal(t, errs, nil) - - intTest = &IntTest{ - Val1: 1, - Val2: 5, - } - - errs = validate.Struct(intTest) - NotEqual(t, errs, nil) - AssertError(t, errs, "IntTest.Val2", "Val2", "ltfield") - - errs = validate.FieldWithValue(int(5), int(1), "ltfield") - Equal(t, errs, nil) - - errs = validate.FieldWithValue(int(1), int(5), "ltfield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "ltfield") - - type UIntTest struct { - Val1 uint `validate:"required"` - Val2 uint `validate:"required,ltfield=Val1"` - } - - uIntTest := &UIntTest{ - Val1: 5, - Val2: 1, - } - - errs = validate.Struct(uIntTest) - Equal(t, errs, nil) - - uIntTest = &UIntTest{ - Val1: 1, - Val2: 5, - } - - errs = validate.Struct(uIntTest) - NotEqual(t, errs, nil) - AssertError(t, errs, "UIntTest.Val2", "Val2", "ltfield") - - errs = validate.FieldWithValue(uint(5), uint(1), "ltfield") - Equal(t, errs, nil) - - errs = validate.FieldWithValue(uint(1), uint(5), "ltfield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "ltfield") - - type FloatTest struct { - Val1 float64 `validate:"required"` - Val2 float64 `validate:"required,ltfield=Val1"` - } - - floatTest := &FloatTest{ - Val1: 5, - Val2: 1, - } - - errs = validate.Struct(floatTest) - Equal(t, errs, nil) - - floatTest = &FloatTest{ - Val1: 1, - Val2: 5, - } - - errs = validate.Struct(floatTest) - NotEqual(t, errs, nil) - AssertError(t, errs, "FloatTest.Val2", "Val2", "ltfield") - - errs = validate.FieldWithValue(float32(5), float32(1), "ltfield") - Equal(t, errs, nil) - - errs = validate.FieldWithValue(float32(1), float32(5), "ltfield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "ltfield") - - errs = validate.FieldWithValue(nil, 5, "ltfield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "ltfield") - - errs = validate.FieldWithValue(1, "T", "ltfield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "ltfield") - - errs = validate.FieldWithValue(1, end, "ltfield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "ltfield") - - type TimeTest2 struct { - Start *time.Time `validate:"required"` - End *time.Time `validate:"required,ltfield=NonExistantField"` - } - - timeTest2 := &TimeTest2{ - Start: &end, - End: &start, - } - - errs = validate.Struct(timeTest2) - NotEqual(t, errs, nil) - AssertError(t, errs, "TimeTest2.End", "End", "ltfield") -} - -func TestLteField(t *testing.T) { - - type TimeTest struct { - Start *time.Time `validate:"required,lte,ltefield=End"` - End *time.Time `validate:"required,lte"` - } - - now := time.Now() - start := now.Add(time.Hour * 24 * -1 * 2) - end := start.Add(time.Hour * 24) - - timeTest := &TimeTest{ - Start: &start, - End: &end, - } - - errs := validate.Struct(timeTest) - Equal(t, errs, nil) - - timeTest = &TimeTest{ - Start: &end, - End: &start, - } - - errs = validate.Struct(timeTest) - NotEqual(t, errs, nil) - AssertError(t, errs, "TimeTest.Start", "Start", "ltefield") - - errs = validate.FieldWithValue(&end, &start, "ltefield") - Equal(t, errs, nil) - - errs = validate.FieldWithValue(&start, &end, "ltefield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "ltefield") - - errs = validate.FieldWithValue(timeTest, &end, "ltefield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "ltefield") - - errs = validate.FieldWithValue("test", "tes", "ltefield") - Equal(t, errs, nil) - - errs = validate.FieldWithValue("test", "test", "ltefield") - Equal(t, errs, nil) - - type IntTest struct { - Val1 int `validate:"required"` - Val2 int `validate:"required,ltefield=Val1"` - } - - intTest := &IntTest{ - Val1: 5, - Val2: 1, - } - - errs = validate.Struct(intTest) - Equal(t, errs, nil) - - intTest = &IntTest{ - Val1: 1, - Val2: 5, - } - - errs = validate.Struct(intTest) - NotEqual(t, errs, nil) - AssertError(t, errs, "IntTest.Val2", "Val2", "ltefield") - - errs = validate.FieldWithValue(int(5), int(1), "ltefield") - Equal(t, errs, nil) - - errs = validate.FieldWithValue(int(1), int(5), "ltefield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "ltefield") - - type UIntTest struct { - Val1 uint `validate:"required"` - Val2 uint `validate:"required,ltefield=Val1"` - } - - uIntTest := &UIntTest{ - Val1: 5, - Val2: 1, - } - - errs = validate.Struct(uIntTest) - Equal(t, errs, nil) - - uIntTest = &UIntTest{ - Val1: 1, - Val2: 5, - } - - errs = validate.Struct(uIntTest) - NotEqual(t, errs, nil) - AssertError(t, errs, "UIntTest.Val2", "Val2", "ltefield") - - errs = validate.FieldWithValue(uint(5), uint(1), "ltefield") - Equal(t, errs, nil) - - errs = validate.FieldWithValue(uint(1), uint(5), "ltefield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "ltefield") - - type FloatTest struct { - Val1 float64 `validate:"required"` - Val2 float64 `validate:"required,ltefield=Val1"` - } - - floatTest := &FloatTest{ - Val1: 5, - Val2: 1, - } - - errs = validate.Struct(floatTest) - Equal(t, errs, nil) - - floatTest = &FloatTest{ - Val1: 1, - Val2: 5, - } - - errs = validate.Struct(floatTest) - NotEqual(t, errs, nil) - AssertError(t, errs, "FloatTest.Val2", "Val2", "ltefield") - - errs = validate.FieldWithValue(float32(5), float32(1), "ltefield") - Equal(t, errs, nil) - - errs = validate.FieldWithValue(float32(1), float32(5), "ltefield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "ltefield") - - errs = validate.FieldWithValue(nil, 5, "ltefield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "ltefield") - - errs = validate.FieldWithValue(1, "T", "ltefield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "ltefield") - - errs = validate.FieldWithValue(1, end, "ltefield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "ltefield") - - type TimeTest2 struct { - Start *time.Time `validate:"required"` - End *time.Time `validate:"required,ltefield=NonExistantField"` - } - - timeTest2 := &TimeTest2{ - Start: &end, - End: &start, - } - - errs = validate.Struct(timeTest2) - NotEqual(t, errs, nil) - AssertError(t, errs, "TimeTest2.End", "End", "ltefield") -} - -func TestGteField(t *testing.T) { - - type TimeTest struct { - Start *time.Time `validate:"required,gte"` - End *time.Time `validate:"required,gte,gtefield=Start"` - } - - now := time.Now() - start := now.Add(time.Hour * 24) - end := start.Add(time.Hour * 24) - - timeTest := &TimeTest{ - Start: &start, - End: &end, - } - - errs := validate.Struct(timeTest) - Equal(t, errs, nil) - - timeTest = &TimeTest{ - Start: &end, - End: &start, - } - - errs = validate.Struct(timeTest) - NotEqual(t, errs, nil) - AssertError(t, errs, "TimeTest.End", "End", "gtefield") - - errs = validate.FieldWithValue(&start, &end, "gtefield") - Equal(t, errs, nil) - - errs = validate.FieldWithValue(&end, &start, "gtefield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "gtefield") - - errs = validate.FieldWithValue(timeTest, &start, "gtefield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "gtefield") - - errs = validate.FieldWithValue("test", "test", "gtefield") - Equal(t, errs, nil) - - errs = validate.FieldWithValue("test", "test bigger", "gtefield") - Equal(t, errs, nil) - - type IntTest struct { - Val1 int `validate:"required"` - Val2 int `validate:"required,gtefield=Val1"` - } - - intTest := &IntTest{ - Val1: 1, - Val2: 5, - } - - errs = validate.Struct(intTest) - Equal(t, errs, nil) - - intTest = &IntTest{ - Val1: 5, - Val2: 1, - } - - errs = validate.Struct(intTest) - NotEqual(t, errs, nil) - AssertError(t, errs, "IntTest.Val2", "Val2", "gtefield") - - errs = validate.FieldWithValue(int(1), int(5), "gtefield") - Equal(t, errs, nil) - - errs = validate.FieldWithValue(int(5), int(1), "gtefield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "gtefield") - - type UIntTest struct { - Val1 uint `validate:"required"` - Val2 uint `validate:"required,gtefield=Val1"` - } - - uIntTest := &UIntTest{ - Val1: 1, - Val2: 5, - } - - errs = validate.Struct(uIntTest) - Equal(t, errs, nil) - - uIntTest = &UIntTest{ - Val1: 5, - Val2: 1, - } - - errs = validate.Struct(uIntTest) - NotEqual(t, errs, nil) - AssertError(t, errs, "UIntTest.Val2", "Val2", "gtefield") - - errs = validate.FieldWithValue(uint(1), uint(5), "gtefield") - Equal(t, errs, nil) - - errs = validate.FieldWithValue(uint(5), uint(1), "gtefield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "gtefield") - - type FloatTest struct { - Val1 float64 `validate:"required"` - Val2 float64 `validate:"required,gtefield=Val1"` - } - - floatTest := &FloatTest{ - Val1: 1, - Val2: 5, - } - - errs = validate.Struct(floatTest) - Equal(t, errs, nil) - - floatTest = &FloatTest{ - Val1: 5, - Val2: 1, - } - - errs = validate.Struct(floatTest) - NotEqual(t, errs, nil) - AssertError(t, errs, "FloatTest.Val2", "Val2", "gtefield") - - errs = validate.FieldWithValue(float32(1), float32(5), "gtefield") - Equal(t, errs, nil) - - errs = validate.FieldWithValue(float32(5), float32(1), "gtefield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "gtefield") - - errs = validate.FieldWithValue(nil, 1, "gtefield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "gtefield") - - errs = validate.FieldWithValue(5, "T", "gtefield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "gtefield") - - errs = validate.FieldWithValue(5, start, "gtefield") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "gtefield") - - type TimeTest2 struct { - Start *time.Time `validate:"required"` - End *time.Time `validate:"required,gtefield=NonExistantField"` - } - - timeTest2 := &TimeTest2{ - Start: &start, - End: &end, - } - - errs = validate.Struct(timeTest2) - NotEqual(t, errs, nil) - AssertError(t, errs, "TimeTest2.End", "End", "gtefield") -} - -func TestValidateByTagAndValue(t *testing.T) { - - val := "test" - field := "test" - errs := validate.FieldWithValue(val, field, "required") - Equal(t, errs, nil) - - 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() - } - - validate.RegisterValidation("isequaltestfunc", fn) - - errs = validate.FieldWithValue(val, field, "isequaltestfunc") - Equal(t, errs, nil) - - val = "unequal" - - errs = validate.FieldWithValue(val, field, "isequaltestfunc") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "isequaltestfunc") -} - -func TestAddFunctions(t *testing.T) { - - fn := func(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { - - return true - } - - config := &Config{ - TagName: "validateme", - } - - validate := New(config) - - errs := validate.RegisterValidation("new", fn) - Equal(t, errs, nil) - - errs = validate.RegisterValidation("", fn) - NotEqual(t, errs, nil) - - validate.RegisterValidation("new", nil) - NotEqual(t, errs, nil) - - errs = validate.RegisterValidation("new", fn) - Equal(t, errs, nil) - - PanicMatches(t, func() { validate.RegisterValidation("dive", fn) }, "Tag 'dive' either contains restricted characters or is the same as a restricted tag needed for normal operation") -} - -func TestChangeTag(t *testing.T) { - - config := &Config{ - TagName: "val", - } - validate := New(config) - - type Test struct { - Name string `val:"len=4"` - } - s := &Test{ - Name: "TEST", - } - - errs := validate.Struct(s) - Equal(t, errs, nil) -} - -func TestUnexposedStruct(t *testing.T) { - - type Test struct { - Name string - unexposed struct { - A string `validate:"required"` - } - } - - s := &Test{ - Name: "TEST", - } - - errs := validate.Struct(s) - Equal(t, errs, nil) -} - -func TestBadParams(t *testing.T) { - - i := 1 - errs := validate.Field(i, "-") - Equal(t, errs, nil) - - PanicMatches(t, func() { validate.Field(i, "len=a") }, "strconv.ParseInt: parsing \"a\": invalid syntax") - PanicMatches(t, func() { validate.Field(i, "len=a") }, "strconv.ParseInt: parsing \"a\": invalid syntax") - - var ui uint = 1 - PanicMatches(t, func() { validate.Field(ui, "len=a") }, "strconv.ParseUint: parsing \"a\": invalid syntax") - - f := 1.23 - PanicMatches(t, func() { validate.Field(f, "len=a") }, "strconv.ParseFloat: parsing \"a\": invalid syntax") -} - -func TestLength(t *testing.T) { - - i := true - PanicMatches(t, func() { validate.Field(i, "len") }, "Bad field type bool") -} - -func TestIsGt(t *testing.T) { - - myMap := map[string]string{} - errs := validate.Field(myMap, "gt=0") - NotEqual(t, errs, nil) - - f := 1.23 - errs = validate.Field(f, "gt=5") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "gt") - - var ui uint = 5 - errs = validate.Field(ui, "gt=10") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "gt") - - i := true - PanicMatches(t, func() { validate.Field(i, "gt") }, "Bad field type bool") - - tm := time.Now().UTC() - tm = tm.Add(time.Hour * 24) - - errs = validate.Field(tm, "gt") - Equal(t, errs, nil) - - t2 := time.Now().UTC() - - errs = validate.Field(t2, "gt") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "gt") - - type Test struct { - Now *time.Time `validate:"gt"` - } - s := &Test{ - Now: &tm, - } - - errs = validate.Struct(s) - Equal(t, errs, nil) - - s = &Test{ - Now: &t2, - } - - errs = validate.Struct(s) - NotEqual(t, errs, nil) - AssertError(t, errs, "Test.Now", "Now", "gt") -} - -func TestIsGte(t *testing.T) { - - i := true - PanicMatches(t, func() { validate.Field(i, "gte") }, "Bad field type bool") - - t1 := time.Now().UTC() - t1 = t1.Add(time.Hour * 24) - - errs := validate.Field(t1, "gte") - Equal(t, errs, nil) - - t2 := time.Now().UTC() - - errs = validate.Field(t2, "gte") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "gte") - - type Test struct { - Now *time.Time `validate:"gte"` - } - s := &Test{ - Now: &t1, - } - - errs = validate.Struct(s) - Equal(t, errs, nil) - - s = &Test{ - Now: &t2, - } - - errs = validate.Struct(s) - NotEqual(t, errs, nil) - AssertError(t, errs, "Test.Now", "Now", "gte") -} - -func TestIsLt(t *testing.T) { - - myMap := map[string]string{} - errs := validate.Field(myMap, "lt=0") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "lt") - - f := 1.23 - errs = validate.Field(f, "lt=0") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "lt") - - var ui uint = 5 - errs = validate.Field(ui, "lt=0") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "lt") - - i := true - PanicMatches(t, func() { validate.Field(i, "lt") }, "Bad field type bool") - - t1 := time.Now().UTC() - - errs = validate.Field(t1, "lt") - Equal(t, errs, nil) - - t2 := time.Now().UTC() - t2 = t2.Add(time.Hour * 24) - - errs = validate.Field(t2, "lt") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "lt") - - type Test struct { - Now *time.Time `validate:"lt"` - } - - s := &Test{ - Now: &t1, - } - - errs = validate.Struct(s) - Equal(t, errs, nil) - - s = &Test{ - Now: &t2, - } - - errs = validate.Struct(s) - NotEqual(t, errs, nil) - AssertError(t, errs, "Test.Now", "Now", "lt") -} - -func TestIsLte(t *testing.T) { - - i := true - PanicMatches(t, func() { validate.Field(i, "lte") }, "Bad field type bool") - - t1 := time.Now().UTC() - - errs := validate.Field(t1, "lte") - Equal(t, errs, nil) - - t2 := time.Now().UTC() - t2 = t2.Add(time.Hour * 24) - - errs = validate.Field(t2, "lte") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "lte") - - type Test struct { - Now *time.Time `validate:"lte"` - } - - s := &Test{ - Now: &t1, - } - - errs = validate.Struct(s) - Equal(t, errs, nil) - - s = &Test{ - Now: &t2, - } - - errs = validate.Struct(s) - NotEqual(t, errs, nil) -} - -func TestUrl(t *testing.T) { - - var tests = []struct { - param string - expected bool - }{ - {"http://foo.bar#com", true}, - {"http://foobar.com", true}, - {"https://foobar.com", true}, - {"foobar.com", false}, - {"http://foobar.coffee/", true}, - {"http://foobar.中文网/", true}, - {"http://foobar.org/", true}, - {"http://foobar.org:8080/", true}, - {"ftp://foobar.ru/", true}, - {"http://user:pass@www.foobar.com/", true}, - {"http://127.0.0.1/", true}, - {"http://duckduckgo.com/?q=%2F", true}, - {"http://localhost:3000/", true}, - {"http://foobar.com/?foo=bar#baz=qux", true}, - {"http://foobar.com?foo=bar", true}, - {"http://www.xn--froschgrn-x9a.net/", true}, - {"", false}, - {"xyz://foobar.com", true}, - {"invalid.", false}, - {".com", false}, - {"rtmp://foobar.com", true}, - {"http://www.foo_bar.com/", true}, - {"http://localhost:3000/", true}, - {"http://foobar.com/#baz", true}, - {"http://foobar.com#baz=qux", true}, - {"http://foobar.com/t$-_.+!*\\'(),", true}, - {"http://www.foobar.com/~foobar", true}, - {"http://www.-foobar.com/", true}, - {"http://www.foo---bar.com/", true}, - {"mailto:someone@example.com", true}, - {"irc://irc.server.org/channel", true}, - {"irc://#channel@network", true}, - {"/abs/test/dir", false}, - {"./rel/test/dir", false}, - } - for i, test := range tests { - - errs := validate.Field(test.param, "url") - - if test.expected { - if !IsEqual(errs, nil) { - t.Fatalf("Index: %d URL failed Error: %s", i, errs) - } - } else { - if IsEqual(errs, nil) { - t.Fatalf("Index: %d URL failed Error: %s", i, errs) - } else { - val := errs.(ValidationErrors)[""] - if val.Tag != "url" { - t.Fatalf("Index: %d URL failed Error: %s", i, errs) - } - } - } - } - - i := 1 - PanicMatches(t, func() { validate.Field(i, "url") }, "Bad field type int") -} - -func TestUri(t *testing.T) { - - var tests = []struct { - param string - expected bool - }{ - {"http://foo.bar#com", true}, - {"http://foobar.com", true}, - {"https://foobar.com", true}, - {"foobar.com", false}, - {"http://foobar.coffee/", true}, - {"http://foobar.中文网/", true}, - {"http://foobar.org/", true}, - {"http://foobar.org:8080/", true}, - {"ftp://foobar.ru/", true}, - {"http://user:pass@www.foobar.com/", true}, - {"http://127.0.0.1/", true}, - {"http://duckduckgo.com/?q=%2F", true}, - {"http://localhost:3000/", true}, - {"http://foobar.com/?foo=bar#baz=qux", true}, - {"http://foobar.com?foo=bar", true}, - {"http://www.xn--froschgrn-x9a.net/", true}, - {"", false}, - {"xyz://foobar.com", true}, - {"invalid.", false}, - {".com", false}, - {"rtmp://foobar.com", true}, - {"http://www.foo_bar.com/", true}, - {"http://localhost:3000/", true}, - {"http://foobar.com#baz=qux", true}, - {"http://foobar.com/t$-_.+!*\\'(),", true}, - {"http://www.foobar.com/~foobar", true}, - {"http://www.-foobar.com/", true}, - {"http://www.foo---bar.com/", true}, - {"mailto:someone@example.com", true}, - {"irc://irc.server.org/channel", true}, - {"irc://#channel@network", true}, - {"/abs/test/dir", true}, - {"./rel/test/dir", false}, - } - for i, test := range tests { - - errs := validate.Field(test.param, "uri") - - if test.expected { - if !IsEqual(errs, nil) { - t.Fatalf("Index: %d URI failed Error: %s", i, errs) - } - } else { - if IsEqual(errs, nil) { - t.Fatalf("Index: %d URI failed Error: %s", i, errs) - } else { - val := errs.(ValidationErrors)[""] - if val.Tag != "uri" { - t.Fatalf("Index: %d URI failed Error: %s", i, errs) - } - } - } - } - - i := 1 - PanicMatches(t, func() { validate.Field(i, "uri") }, "Bad field type int") -} - -func TestOrTag(t *testing.T) { - s := "rgba(0,31,255,0.5)" - errs := validate.Field(s, "rgb|rgba") - Equal(t, errs, nil) - - s = "rgba(0,31,255,0.5)" - errs = validate.Field(s, "rgb|rgba|len=18") - Equal(t, errs, nil) - - s = "this ain't right" - errs = validate.Field(s, "rgb|rgba") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "rgb|rgba") - - s = "this ain't right" - errs = validate.Field(s, "rgb|rgba|len=10") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "rgb|rgba|len") - - s = "this is right" - errs = validate.Field(s, "rgb|rgba|len=13") - Equal(t, errs, nil) - - s = "" - errs = validate.Field(s, "omitempty,rgb|rgba") - Equal(t, errs, nil) - - s = "this is right, but a blank or isn't" - - PanicMatches(t, func() { validate.Field(s, "rgb||len=13") }, "Invalid validation tag on field") - PanicMatches(t, func() { validate.Field(s, "rgb|rgbaa|len=13") }, "Undefined validation function on field") -} - -func TestHsla(t *testing.T) { - - s := "hsla(360,100%,100%,1)" - errs := validate.Field(s, "hsla") - Equal(t, errs, nil) - - s = "hsla(360,100%,100%,0.5)" - errs = validate.Field(s, "hsla") - Equal(t, errs, nil) - - s = "hsla(0,0%,0%, 0)" - errs = validate.Field(s, "hsla") - Equal(t, errs, nil) - - s = "hsl(361,100%,50%,1)" - errs = validate.Field(s, "hsla") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "hsla") - - s = "hsl(361,100%,50%)" - errs = validate.Field(s, "hsla") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "hsla") - - s = "hsla(361,100%,50%)" - errs = validate.Field(s, "hsla") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "hsla") - - s = "hsla(360,101%,50%)" - errs = validate.Field(s, "hsla") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "hsla") - - s = "hsla(360,100%,101%)" - errs = validate.Field(s, "hsla") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "hsla") - - i := 1 - validate.Field(i, "hsla") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "hsla") -} - -func TestHsl(t *testing.T) { - - s := "hsl(360,100%,50%)" - errs := validate.Field(s, "hsl") - Equal(t, errs, nil) - - s = "hsl(0,0%,0%)" - errs = validate.Field(s, "hsl") - Equal(t, errs, nil) - - s = "hsl(361,100%,50%)" - errs = validate.Field(s, "hsl") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "hsl") - - s = "hsl(361,101%,50%)" - errs = validate.Field(s, "hsl") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "hsl") - - s = "hsl(361,100%,101%)" - errs = validate.Field(s, "hsl") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "hsl") +// errs = validate.Field(t2, "gt") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "gt") - s = "hsl(-10,100%,100%)" - errs = validate.Field(s, "hsl") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "hsl") - - i := 1 - errs = validate.Field(i, "hsl") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "hsl") -} - -func TestRgba(t *testing.T) { - - s := "rgba(0,31,255,0.5)" - errs := validate.Field(s, "rgba") - Equal(t, errs, nil) - - s = "rgba(0,31,255,0.12)" - errs = validate.Field(s, "rgba") - Equal(t, errs, nil) - - s = "rgba(12%,55%,100%,0.12)" - errs = validate.Field(s, "rgba") - Equal(t, errs, nil) - - s = "rgba( 0, 31, 255, 0.5)" - errs = validate.Field(s, "rgba") - Equal(t, errs, nil) - - s = "rgba(12%,55,100%,0.12)" - errs = validate.Field(s, "rgba") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "rgba") - - s = "rgb(0, 31, 255)" - errs = validate.Field(s, "rgba") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "rgba") - - s = "rgb(1,349,275,0.5)" - errs = validate.Field(s, "rgba") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "rgba") - - s = "rgb(01,31,255,0.5)" - errs = validate.Field(s, "rgba") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "rgba") - - i := 1 - errs = validate.Field(i, "rgba") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "rgba") -} - -func TestRgb(t *testing.T) { - - s := "rgb(0,31,255)" - errs := validate.Field(s, "rgb") - Equal(t, errs, nil) - - s = "rgb(0, 31, 255)" - errs = validate.Field(s, "rgb") - Equal(t, errs, nil) - - s = "rgb(10%, 50%, 100%)" - errs = validate.Field(s, "rgb") - Equal(t, errs, nil) - - s = "rgb(10%, 50%, 55)" - errs = validate.Field(s, "rgb") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "rgb") - - s = "rgb(1,349,275)" - errs = validate.Field(s, "rgb") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "rgb") - - s = "rgb(01,31,255)" - errs = validate.Field(s, "rgb") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "rgb") - - s = "rgba(0,31,255)" - errs = validate.Field(s, "rgb") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "rgb") - - i := 1 - errs = validate.Field(i, "rgb") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "rgb") -} - -func TestEmail(t *testing.T) { - - s := "test@mail.com" - errs := validate.Field(s, "email") - Equal(t, errs, nil) - - s = "Dörte@Sörensen.example.com" - errs = validate.Field(s, "email") - Equal(t, errs, nil) - - s = "θσερ@εχαμπλε.ψομ" - errs = validate.Field(s, "email") - Equal(t, errs, nil) - - s = "юзер@екзампл.ком" - errs = validate.Field(s, "email") - Equal(t, errs, nil) - - s = "उपयोगकर्ता@उदाहरण.कॉम" - errs = validate.Field(s, "email") - Equal(t, errs, nil) - - s = "用户@例子.广告" - errs = validate.Field(s, "email") - Equal(t, errs, nil) - - s = "" - errs = validate.Field(s, "email") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "email") - - s = "test@email" - errs = validate.Field(s, "email") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "email") - - s = "test@email." - errs = validate.Field(s, "email") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "email") - - s = "@email.com" - errs = validate.Field(s, "email") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "email") - - i := true - errs = validate.Field(i, "email") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "email") -} - -func TestHexColor(t *testing.T) { - - s := "#fff" - errs := validate.Field(s, "hexcolor") - Equal(t, errs, nil) - - s = "#c2c2c2" - errs = validate.Field(s, "hexcolor") - Equal(t, errs, nil) - - s = "fff" - errs = validate.Field(s, "hexcolor") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "hexcolor") - - s = "fffFF" - errs = validate.Field(s, "hexcolor") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "hexcolor") - - i := true - errs = validate.Field(i, "hexcolor") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "hexcolor") -} - -func TestHexadecimal(t *testing.T) { - - s := "ff0044" - errs := validate.Field(s, "hexadecimal") - Equal(t, errs, nil) - - s = "abcdefg" - errs = validate.Field(s, "hexadecimal") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "hexadecimal") - - i := true - errs = validate.Field(i, "hexadecimal") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "hexadecimal") -} - -func TestNumber(t *testing.T) { - - s := "1" - errs := validate.Field(s, "number") - Equal(t, errs, nil) - - s = "+1" - errs = validate.Field(s, "number") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "number") - - s = "-1" - errs = validate.Field(s, "number") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "number") - - s = "1.12" - errs = validate.Field(s, "number") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "number") - - s = "+1.12" - errs = validate.Field(s, "number") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "number") - - s = "-1.12" - errs = validate.Field(s, "number") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "number") - - s = "1." - errs = validate.Field(s, "number") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "number") - - s = "1.o" - errs = validate.Field(s, "number") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "number") - - i := 1 - errs = validate.Field(i, "number") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "number") -} - -func TestNumeric(t *testing.T) { - - s := "1" - errs := validate.Field(s, "numeric") - Equal(t, errs, nil) - - s = "+1" - errs = validate.Field(s, "numeric") - Equal(t, errs, nil) - - s = "-1" - errs = validate.Field(s, "numeric") - Equal(t, errs, nil) - - s = "1.12" - errs = validate.Field(s, "numeric") - Equal(t, errs, nil) +// type Test struct { +// Now *time.Time `validate:"gt"` +// } +// s := &Test{ +// Now: &tm, +// } - s = "+1.12" - errs = validate.Field(s, "numeric") - Equal(t, errs, nil) +// errs = validate.Struct(s) +// Equal(t, errs, nil) - s = "-1.12" - errs = validate.Field(s, "numeric") - Equal(t, errs, nil) +// s = &Test{ +// Now: &t2, +// } - s = "1." - errs = validate.Field(s, "numeric") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "numeric") +// errs = validate.Struct(s) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "Test.Now", "Now", "gt") +// } - s = "1.o" - errs = validate.Field(s, "numeric") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "numeric") +// func TestIsGte(t *testing.T) { - i := 1 - errs = validate.Field(i, "numeric") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "numeric") -} +// i := true +// PanicMatches(t, func() { validate.Field(i, "gte") }, "Bad field type bool") -func TestAlphaNumeric(t *testing.T) { +// t1 := time.Now().UTC() +// t1 = t1.Add(time.Hour * 24) - s := "abcd123" - errs := validate.Field(s, "alphanum") - Equal(t, errs, nil) +// errs := validate.Field(t1, "gte") +// Equal(t, errs, nil) - s = "abc!23" - errs = validate.Field(s, "alphanum") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "alphanum") +// t2 := time.Now().UTC() - errs = validate.Field(1, "alphanum") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "alphanum") -} +// errs = validate.Field(t2, "gte") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "gte") -func TestAlpha(t *testing.T) { +// type Test struct { +// Now *time.Time `validate:"gte"` +// } +// s := &Test{ +// Now: &t1, +// } - s := "abcd" - errs := validate.Field(s, "alpha") - Equal(t, errs, nil) +// errs = validate.Struct(s) +// Equal(t, errs, nil) - s = "abc®" - errs = validate.Field(s, "alpha") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "alpha") +// s = &Test{ +// Now: &t2, +// } - s = "abc÷" - errs = validate.Field(s, "alpha") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "alpha") +// errs = validate.Struct(s) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "Test.Now", "Now", "gte") +// } - s = "abc1" - errs = validate.Field(s, "alpha") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "alpha") +// func TestIsLt(t *testing.T) { - errs = validate.Field(1, "alpha") - NotEqual(t, errs, nil) - AssertError(t, errs, "", "", "alpha") +// myMap := map[string]string{} +// errs := validate.Field(myMap, "lt=0") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "lt") -} +// f := 1.23 +// errs = validate.Field(f, "lt=0") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "lt") -func TestStructStringValidation(t *testing.T) { - - tSuccess := &TestString{ - Required: "Required", - Len: "length==10", - Min: "min=1", - Max: "1234567890", - MinMax: "12345", - Lt: "012345678", - Lte: "0123456789", - Gt: "01234567890", - Gte: "0123456789", - OmitEmpty: "", - Sub: &SubTest{ - Test: "1", - }, - SubIgnore: &SubTest{ - Test: "", - }, - Anonymous: struct { - A string `validate:"required"` - }{ - A: "1", - }, - Iface: &Impl{ - F: "123", - }, - } +// var ui uint = 5 +// errs = validate.Field(ui, "lt=0") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "lt") + +// i := true +// PanicMatches(t, func() { validate.Field(i, "lt") }, "Bad field type bool") + +// t1 := time.Now().UTC() + +// errs = validate.Field(t1, "lt") +// Equal(t, errs, nil) + +// t2 := time.Now().UTC() +// t2 = t2.Add(time.Hour * 24) + +// errs = validate.Field(t2, "lt") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "lt") + +// type Test struct { +// Now *time.Time `validate:"lt"` +// } + +// s := &Test{ +// Now: &t1, +// } + +// errs = validate.Struct(s) +// Equal(t, errs, nil) + +// s = &Test{ +// Now: &t2, +// } + +// errs = validate.Struct(s) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "Test.Now", "Now", "lt") +// } + +// func TestIsLte(t *testing.T) { + +// i := true +// PanicMatches(t, func() { validate.Field(i, "lte") }, "Bad field type bool") + +// t1 := time.Now().UTC() + +// errs := validate.Field(t1, "lte") +// Equal(t, errs, nil) + +// t2 := time.Now().UTC() +// t2 = t2.Add(time.Hour * 24) + +// errs = validate.Field(t2, "lte") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "lte") + +// type Test struct { +// Now *time.Time `validate:"lte"` +// } + +// s := &Test{ +// Now: &t1, +// } + +// errs = validate.Struct(s) +// Equal(t, errs, nil) + +// s = &Test{ +// Now: &t2, +// } + +// errs = validate.Struct(s) +// NotEqual(t, errs, nil) +// } + +// func TestUrl(t *testing.T) { + +// var tests = []struct { +// param string +// expected bool +// }{ +// {"http://foo.bar#com", true}, +// {"http://foobar.com", true}, +// {"https://foobar.com", true}, +// {"foobar.com", false}, +// {"http://foobar.coffee/", true}, +// {"http://foobar.中文网/", true}, +// {"http://foobar.org/", true}, +// {"http://foobar.org:8080/", true}, +// {"ftp://foobar.ru/", true}, +// {"http://user:pass@www.foobar.com/", true}, +// {"http://127.0.0.1/", true}, +// {"http://duckduckgo.com/?q=%2F", true}, +// {"http://localhost:3000/", true}, +// {"http://foobar.com/?foo=bar#baz=qux", true}, +// {"http://foobar.com?foo=bar", true}, +// {"http://www.xn--froschgrn-x9a.net/", true}, +// {"", false}, +// {"xyz://foobar.com", true}, +// {"invalid.", false}, +// {".com", false}, +// {"rtmp://foobar.com", true}, +// {"http://www.foo_bar.com/", true}, +// {"http://localhost:3000/", true}, +// {"http://foobar.com/#baz", true}, +// {"http://foobar.com#baz=qux", true}, +// {"http://foobar.com/t$-_.+!*\\'(),", true}, +// {"http://www.foobar.com/~foobar", true}, +// {"http://www.-foobar.com/", true}, +// {"http://www.foo---bar.com/", true}, +// {"mailto:someone@example.com", true}, +// {"irc://irc.server.org/channel", true}, +// {"irc://#channel@network", true}, +// {"/abs/test/dir", false}, +// {"./rel/test/dir", false}, +// } +// for i, test := range tests { + +// errs := validate.Field(test.param, "url") + +// if test.expected { +// if !IsEqual(errs, nil) { +// t.Fatalf("Index: %d URL failed Error: %s", i, errs) +// } +// } else { +// if IsEqual(errs, nil) { +// t.Fatalf("Index: %d URL failed Error: %s", i, errs) +// } else { +// val := errs.(ValidationErrors)[""] +// if val.Tag != "url" { +// t.Fatalf("Index: %d URL failed Error: %s", i, errs) +// } +// } +// } +// } + +// i := 1 +// PanicMatches(t, func() { validate.Field(i, "url") }, "Bad field type int") +// } + +// func TestUri(t *testing.T) { + +// var tests = []struct { +// param string +// expected bool +// }{ +// {"http://foo.bar#com", true}, +// {"http://foobar.com", true}, +// {"https://foobar.com", true}, +// {"foobar.com", false}, +// {"http://foobar.coffee/", true}, +// {"http://foobar.中文网/", true}, +// {"http://foobar.org/", true}, +// {"http://foobar.org:8080/", true}, +// {"ftp://foobar.ru/", true}, +// {"http://user:pass@www.foobar.com/", true}, +// {"http://127.0.0.1/", true}, +// {"http://duckduckgo.com/?q=%2F", true}, +// {"http://localhost:3000/", true}, +// {"http://foobar.com/?foo=bar#baz=qux", true}, +// {"http://foobar.com?foo=bar", true}, +// {"http://www.xn--froschgrn-x9a.net/", true}, +// {"", false}, +// {"xyz://foobar.com", true}, +// {"invalid.", false}, +// {".com", false}, +// {"rtmp://foobar.com", true}, +// {"http://www.foo_bar.com/", true}, +// {"http://localhost:3000/", true}, +// {"http://foobar.com#baz=qux", true}, +// {"http://foobar.com/t$-_.+!*\\'(),", true}, +// {"http://www.foobar.com/~foobar", true}, +// {"http://www.-foobar.com/", true}, +// {"http://www.foo---bar.com/", true}, +// {"mailto:someone@example.com", true}, +// {"irc://irc.server.org/channel", true}, +// {"irc://#channel@network", true}, +// {"/abs/test/dir", true}, +// {"./rel/test/dir", false}, +// } +// for i, test := range tests { + +// errs := validate.Field(test.param, "uri") + +// if test.expected { +// if !IsEqual(errs, nil) { +// t.Fatalf("Index: %d URI failed Error: %s", i, errs) +// } +// } else { +// if IsEqual(errs, nil) { +// t.Fatalf("Index: %d URI failed Error: %s", i, errs) +// } else { +// val := errs.(ValidationErrors)[""] +// if val.Tag != "uri" { +// t.Fatalf("Index: %d URI failed Error: %s", i, errs) +// } +// } +// } +// } + +// i := 1 +// PanicMatches(t, func() { validate.Field(i, "uri") }, "Bad field type int") +// } + +// func TestOrTag(t *testing.T) { +// s := "rgba(0,31,255,0.5)" +// errs := validate.Field(s, "rgb|rgba") +// Equal(t, errs, nil) + +// s = "rgba(0,31,255,0.5)" +// errs = validate.Field(s, "rgb|rgba|len=18") +// Equal(t, errs, nil) + +// s = "this ain't right" +// errs = validate.Field(s, "rgb|rgba") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "rgb|rgba") + +// s = "this ain't right" +// errs = validate.Field(s, "rgb|rgba|len=10") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "rgb|rgba|len") + +// s = "this is right" +// errs = validate.Field(s, "rgb|rgba|len=13") +// Equal(t, errs, nil) + +// s = "" +// errs = validate.Field(s, "omitempty,rgb|rgba") +// Equal(t, errs, nil) + +// s = "this is right, but a blank or isn't" + +// PanicMatches(t, func() { validate.Field(s, "rgb||len=13") }, "Invalid validation tag on field") +// PanicMatches(t, func() { validate.Field(s, "rgb|rgbaa|len=13") }, "Undefined validation function on field") +// } + +// func TestHsla(t *testing.T) { + +// s := "hsla(360,100%,100%,1)" +// errs := validate.Field(s, "hsla") +// Equal(t, errs, nil) + +// s = "hsla(360,100%,100%,0.5)" +// errs = validate.Field(s, "hsla") +// Equal(t, errs, nil) + +// s = "hsla(0,0%,0%, 0)" +// errs = validate.Field(s, "hsla") +// Equal(t, errs, nil) + +// s = "hsl(361,100%,50%,1)" +// errs = validate.Field(s, "hsla") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "hsla") + +// s = "hsl(361,100%,50%)" +// errs = validate.Field(s, "hsla") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "hsla") + +// s = "hsla(361,100%,50%)" +// errs = validate.Field(s, "hsla") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "hsla") + +// s = "hsla(360,101%,50%)" +// errs = validate.Field(s, "hsla") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "hsla") + +// s = "hsla(360,100%,101%)" +// errs = validate.Field(s, "hsla") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "hsla") + +// i := 1 +// validate.Field(i, "hsla") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "hsla") +// } + +// func TestHsl(t *testing.T) { + +// s := "hsl(360,100%,50%)" +// errs := validate.Field(s, "hsl") +// Equal(t, errs, nil) + +// s = "hsl(0,0%,0%)" +// errs = validate.Field(s, "hsl") +// Equal(t, errs, nil) + +// s = "hsl(361,100%,50%)" +// errs = validate.Field(s, "hsl") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "hsl") + +// s = "hsl(361,101%,50%)" +// errs = validate.Field(s, "hsl") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "hsl") + +// s = "hsl(361,100%,101%)" +// errs = validate.Field(s, "hsl") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "hsl") + +// s = "hsl(-10,100%,100%)" +// errs = validate.Field(s, "hsl") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "hsl") + +// i := 1 +// errs = validate.Field(i, "hsl") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "hsl") +// } + +// func TestRgba(t *testing.T) { + +// s := "rgba(0,31,255,0.5)" +// errs := validate.Field(s, "rgba") +// Equal(t, errs, nil) + +// s = "rgba(0,31,255,0.12)" +// errs = validate.Field(s, "rgba") +// Equal(t, errs, nil) + +// s = "rgba(12%,55%,100%,0.12)" +// errs = validate.Field(s, "rgba") +// Equal(t, errs, nil) + +// s = "rgba( 0, 31, 255, 0.5)" +// errs = validate.Field(s, "rgba") +// Equal(t, errs, nil) + +// s = "rgba(12%,55,100%,0.12)" +// errs = validate.Field(s, "rgba") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "rgba") + +// s = "rgb(0, 31, 255)" +// errs = validate.Field(s, "rgba") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "rgba") + +// s = "rgb(1,349,275,0.5)" +// errs = validate.Field(s, "rgba") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "rgba") + +// s = "rgb(01,31,255,0.5)" +// errs = validate.Field(s, "rgba") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "rgba") + +// i := 1 +// errs = validate.Field(i, "rgba") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "rgba") +// } + +// func TestRgb(t *testing.T) { + +// s := "rgb(0,31,255)" +// errs := validate.Field(s, "rgb") +// Equal(t, errs, nil) + +// s = "rgb(0, 31, 255)" +// errs = validate.Field(s, "rgb") +// Equal(t, errs, nil) + +// s = "rgb(10%, 50%, 100%)" +// errs = validate.Field(s, "rgb") +// Equal(t, errs, nil) + +// s = "rgb(10%, 50%, 55)" +// errs = validate.Field(s, "rgb") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "rgb") + +// s = "rgb(1,349,275)" +// errs = validate.Field(s, "rgb") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "rgb") + +// s = "rgb(01,31,255)" +// errs = validate.Field(s, "rgb") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "rgb") + +// s = "rgba(0,31,255)" +// errs = validate.Field(s, "rgb") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "rgb") + +// i := 1 +// errs = validate.Field(i, "rgb") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "rgb") +// } + +// func TestEmail(t *testing.T) { + +// s := "test@mail.com" +// errs := validate.Field(s, "email") +// Equal(t, errs, nil) + +// s = "Dörte@Sörensen.example.com" +// errs = validate.Field(s, "email") +// Equal(t, errs, nil) + +// s = "θσερ@εχαμπλε.ψομ" +// errs = validate.Field(s, "email") +// Equal(t, errs, nil) + +// s = "юзер@екзампл.ком" +// errs = validate.Field(s, "email") +// Equal(t, errs, nil) + +// s = "उपयोगकर्ता@उदाहरण.कॉम" +// errs = validate.Field(s, "email") +// Equal(t, errs, nil) + +// s = "用户@例子.广告" +// errs = validate.Field(s, "email") +// Equal(t, errs, nil) + +// s = "" +// errs = validate.Field(s, "email") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "email") + +// s = "test@email" +// errs = validate.Field(s, "email") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "email") + +// s = "test@email." +// errs = validate.Field(s, "email") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "email") + +// s = "@email.com" +// errs = validate.Field(s, "email") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "email") + +// i := true +// errs = validate.Field(i, "email") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "email") +// } + +// func TestHexColor(t *testing.T) { + +// s := "#fff" +// errs := validate.Field(s, "hexcolor") +// Equal(t, errs, nil) + +// s = "#c2c2c2" +// errs = validate.Field(s, "hexcolor") +// Equal(t, errs, nil) + +// s = "fff" +// errs = validate.Field(s, "hexcolor") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "hexcolor") + +// s = "fffFF" +// errs = validate.Field(s, "hexcolor") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "hexcolor") + +// i := true +// errs = validate.Field(i, "hexcolor") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "hexcolor") +// } + +// func TestHexadecimal(t *testing.T) { + +// s := "ff0044" +// errs := validate.Field(s, "hexadecimal") +// Equal(t, errs, nil) + +// s = "abcdefg" +// errs = validate.Field(s, "hexadecimal") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "hexadecimal") + +// i := true +// errs = validate.Field(i, "hexadecimal") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "hexadecimal") +// } + +// func TestNumber(t *testing.T) { + +// s := "1" +// errs := validate.Field(s, "number") +// Equal(t, errs, nil) + +// s = "+1" +// errs = validate.Field(s, "number") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "number") + +// s = "-1" +// errs = validate.Field(s, "number") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "number") + +// s = "1.12" +// errs = validate.Field(s, "number") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "number") + +// s = "+1.12" +// errs = validate.Field(s, "number") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "number") + +// s = "-1.12" +// errs = validate.Field(s, "number") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "number") + +// s = "1." +// errs = validate.Field(s, "number") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "number") + +// s = "1.o" +// errs = validate.Field(s, "number") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "number") + +// i := 1 +// errs = validate.Field(i, "number") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "number") +// } + +// func TestNumeric(t *testing.T) { + +// s := "1" +// errs := validate.Field(s, "numeric") +// Equal(t, errs, nil) + +// s = "+1" +// errs = validate.Field(s, "numeric") +// Equal(t, errs, nil) + +// s = "-1" +// errs = validate.Field(s, "numeric") +// Equal(t, errs, nil) + +// s = "1.12" +// errs = validate.Field(s, "numeric") +// Equal(t, errs, nil) + +// s = "+1.12" +// errs = validate.Field(s, "numeric") +// Equal(t, errs, nil) + +// s = "-1.12" +// errs = validate.Field(s, "numeric") +// Equal(t, errs, nil) + +// s = "1." +// errs = validate.Field(s, "numeric") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "numeric") + +// s = "1.o" +// errs = validate.Field(s, "numeric") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "numeric") + +// i := 1 +// errs = validate.Field(i, "numeric") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "numeric") +// } + +// func TestAlphaNumeric(t *testing.T) { + +// s := "abcd123" +// errs := validate.Field(s, "alphanum") +// Equal(t, errs, nil) + +// s = "abc!23" +// errs = validate.Field(s, "alphanum") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "alphanum") + +// errs = validate.Field(1, "alphanum") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "alphanum") +// } + +// func TestAlpha(t *testing.T) { + +// s := "abcd" +// errs := validate.Field(s, "alpha") +// Equal(t, errs, nil) + +// s = "abc®" +// errs = validate.Field(s, "alpha") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "alpha") + +// s = "abc÷" +// errs = validate.Field(s, "alpha") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "alpha") + +// s = "abc1" +// errs = validate.Field(s, "alpha") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "alpha") + +// errs = validate.Field(1, "alpha") +// NotEqual(t, errs, nil) +// AssertError(t, errs, "", "", "alpha") + +// } + +// func TestStructStringValidation(t *testing.T) { + +// tSuccess := &TestString{ +// Required: "Required", +// Len: "length==10", +// Min: "min=1", +// Max: "1234567890", +// MinMax: "12345", +// Lt: "012345678", +// Lte: "0123456789", +// Gt: "01234567890", +// Gte: "0123456789", +// OmitEmpty: "", +// Sub: &SubTest{ +// Test: "1", +// }, +// SubIgnore: &SubTest{ +// Test: "", +// }, +// Anonymous: struct { +// A string `validate:"required"` +// }{ +// A: "1", +// }, +// Iface: &Impl{ +// F: "123", +// }, +// } + +// errs := validate.Struct(tSuccess) +// Equal(t, errs, nil) + +// tFail := &TestString{ +// Required: "", +// Len: "", +// Min: "", +// Max: "12345678901", +// MinMax: "", +// Lt: "0123456789", +// Lte: "01234567890", +// Gt: "1", +// Gte: "1", +// OmitEmpty: "12345678901", +// Sub: &SubTest{ +// Test: "", +// }, +// Anonymous: struct { +// A string `validate:"required"` +// }{ +// A: "", +// }, +// Iface: &Impl{ +// F: "12", +// }, +// } + +// errs = validate.Struct(tFail) + +// // Assert Top Level +// NotEqual(t, errs, nil) +// Equal(t, len(errs.(ValidationErrors)), 13) + +// // Assert Fields +// AssertError(t, errs, "TestString.Required", "Required", "required") +// AssertError(t, errs, "TestString.Len", "Len", "len") +// AssertError(t, errs, "TestString.Min", "Min", "min") +// AssertError(t, errs, "TestString.Max", "Max", "max") +// AssertError(t, errs, "TestString.MinMax", "MinMax", "min") +// AssertError(t, errs, "TestString.Lt", "Lt", "lt") +// AssertError(t, errs, "TestString.Lte", "Lte", "lte") +// AssertError(t, errs, "TestString.Gt", "Gt", "gt") +// AssertError(t, errs, "TestString.Gte", "Gte", "gte") +// AssertError(t, errs, "TestString.OmitEmpty", "OmitEmpty", "max") + +// // Nested Struct Field Errs +// AssertError(t, errs, "TestString.Anonymous.A", "A", "required") +// AssertError(t, errs, "TestString.Sub.Test", "Test", "required") +// AssertError(t, errs, "TestString.Iface.F", "F", "len") +// } - errs := validate.Struct(tSuccess) - Equal(t, errs, nil) +func TestStructInt32Validation(t *testing.T) { - tFail := &TestString{ - Required: "", - Len: "", - Min: "", - Max: "12345678901", - MinMax: "", - Lt: "0123456789", - Lte: "01234567890", - Gt: "1", - Gte: "1", - OmitEmpty: "12345678901", - Sub: &SubTest{ - Test: "", - }, - Anonymous: struct { - A string `validate:"required"` - }{ - A: "", - }, - Iface: &Impl{ - F: "12", - }, + type TestInt32 struct { + Required int `validate:"required"` + Len int `validate:"len=10"` + Min int `validate:"min=1"` + Max int `validate:"max=10"` + MinMax int `validate:"min=1,max=10"` + Lt int `validate:"lt=10"` + Lte int `validate:"lte=10"` + Gt int `validate:"gt=10"` + Gte int `validate:"gte=10"` + OmitEmpty int `validate:"omitempty,min=1,max=10"` } - errs = validate.Struct(tFail) - - // Assert Top Level - NotEqual(t, errs, nil) - Equal(t, len(errs.(ValidationErrors)), 13) - - // Assert Fields - AssertError(t, errs, "TestString.Required", "Required", "required") - AssertError(t, errs, "TestString.Len", "Len", "len") - AssertError(t, errs, "TestString.Min", "Min", "min") - AssertError(t, errs, "TestString.Max", "Max", "max") - AssertError(t, errs, "TestString.MinMax", "MinMax", "min") - AssertError(t, errs, "TestString.Lt", "Lt", "lt") - AssertError(t, errs, "TestString.Lte", "Lte", "lte") - AssertError(t, errs, "TestString.Gt", "Gt", "gt") - AssertError(t, errs, "TestString.Gte", "Gte", "gte") - AssertError(t, errs, "TestString.OmitEmpty", "OmitEmpty", "max") - - // Nested Struct Field Errs - AssertError(t, errs, "TestString.Anonymous.A", "A", "required") - AssertError(t, errs, "TestString.Sub.Test", "Test", "required") - AssertError(t, errs, "TestString.Iface.F", "F", "len") -} - -func TestStructInt32Validation(t *testing.T) { - tSuccess := &TestInt32{ Required: 1, Len: 10, @@ -5637,6 +5643,7 @@ func TestStructInt32Validation(t *testing.T) { OmitEmpty: 0, } + validate := New() errs := validate.Struct(tSuccess) Equal(t, errs, nil) @@ -5672,229 +5679,229 @@ func TestStructInt32Validation(t *testing.T) { AssertError(t, errs, "TestInt32.OmitEmpty", "OmitEmpty", "max") } -func TestStructUint64Validation(t *testing.T) { - - tSuccess := &TestUint64{ - Required: 1, - Len: 10, - Min: 1, - Max: 10, - MinMax: 5, - OmitEmpty: 0, - } - - errs := validate.Struct(tSuccess) - Equal(t, errs, nil) - - tFail := &TestUint64{ - Required: 0, - Len: 11, - Min: 0, - Max: 11, - MinMax: 0, - OmitEmpty: 11, - } - - errs = validate.Struct(tFail) - - // Assert Top Level - NotEqual(t, errs, nil) - Equal(t, len(errs.(ValidationErrors)), 6) - - // Assert Fields - AssertError(t, errs, "TestUint64.Required", "Required", "required") - AssertError(t, errs, "TestUint64.Len", "Len", "len") - AssertError(t, errs, "TestUint64.Min", "Min", "min") - AssertError(t, errs, "TestUint64.Max", "Max", "max") - AssertError(t, errs, "TestUint64.MinMax", "MinMax", "min") - AssertError(t, errs, "TestUint64.OmitEmpty", "OmitEmpty", "max") -} - -func TestStructFloat64Validation(t *testing.T) { - - tSuccess := &TestFloat64{ - Required: 1, - Len: 10, - Min: 1, - Max: 10, - MinMax: 5, - OmitEmpty: 0, - } - - errs := validate.Struct(tSuccess) - Equal(t, errs, nil) - - tFail := &TestFloat64{ - Required: 0, - Len: 11, - Min: 0, - Max: 11, - MinMax: 0, - OmitEmpty: 11, - } - - errs = validate.Struct(tFail) - - // Assert Top Level - NotEqual(t, errs, nil) - Equal(t, len(errs.(ValidationErrors)), 6) - - // Assert Fields - AssertError(t, errs, "TestFloat64.Required", "Required", "required") - AssertError(t, errs, "TestFloat64.Len", "Len", "len") - AssertError(t, errs, "TestFloat64.Min", "Min", "min") - AssertError(t, errs, "TestFloat64.Max", "Max", "max") - AssertError(t, errs, "TestFloat64.MinMax", "MinMax", "min") - AssertError(t, errs, "TestFloat64.OmitEmpty", "OmitEmpty", "max") -} - -func TestStructSliceValidation(t *testing.T) { - - tSuccess := &TestSlice{ - Required: []int{1}, - Len: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}, - Min: []int{1, 2}, - Max: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}, - MinMax: []int{1, 2, 3, 4, 5}, - OmitEmpty: nil, - } - - errs := validate.Struct(tSuccess) - Equal(t, errs, nil) - - tFail := &TestSlice{ - Required: nil, - Len: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1}, - Min: []int{}, - Max: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1}, - MinMax: []int{}, - OmitEmpty: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1}, - } - - errs = validate.Struct(tFail) - NotEqual(t, errs, nil) - Equal(t, len(errs.(ValidationErrors)), 6) - - // Assert Field Errors - AssertError(t, errs, "TestSlice.Required", "Required", "required") - AssertError(t, errs, "TestSlice.Len", "Len", "len") - AssertError(t, errs, "TestSlice.Min", "Min", "min") - AssertError(t, errs, "TestSlice.Max", "Max", "max") - AssertError(t, errs, "TestSlice.MinMax", "MinMax", "min") - AssertError(t, errs, "TestSlice.OmitEmpty", "OmitEmpty", "max") -} - -func TestInvalidStruct(t *testing.T) { - s := &SubTest{ - Test: "1", - } - - PanicMatches(t, func() { validate.Struct(s.Test) }, "value passed for validation is not a struct") -} - -func TestInvalidValidatorFunction(t *testing.T) { - s := &SubTest{ - Test: "1", - } - - PanicMatches(t, func() { validate.Field(s.Test, "zzxxBadFunction") }, "Undefined validation function on field") -} - -func TestCustomFieldName(t *testing.T) { - type A struct { - B string `schema:"b" validate:"required"` - C string `schema:"c" validate:"required"` - D []bool `schema:"d" validate:"required"` - E string `schema:"-" validate:"required"` - } - - a := &A{} - - errs := New(&Config{TagName: "validate", FieldNameTag: "schema"}).Struct(a).(ValidationErrors) - NotEqual(t, errs, nil) - Equal(t, len(errs), 4) - Equal(t, errs["A.B"].Name, "b") - Equal(t, errs["A.C"].Name, "c") - Equal(t, errs["A.D"].Name, "d") - Equal(t, errs["A.E"].Name, "E") - - errs = New(&Config{TagName: "validate"}).Struct(a).(ValidationErrors) - NotEqual(t, errs, nil) - Equal(t, len(errs), 4) - Equal(t, errs["A.B"].Name, "B") - Equal(t, errs["A.C"].Name, "C") - Equal(t, errs["A.D"].Name, "D") - Equal(t, errs["A.E"].Name, "E") -} - -func TestMutipleRecursiveExtractStructCache(t *testing.T) { - - type Recursive struct { - Field *string `validate:"exists,required,len=5,ne=string"` - } - - var test Recursive - - current := reflect.ValueOf(test) - name := "Recursive" - proceed := make(chan struct{}) - - sc := validate.extractStructCache(current, name) - ptr := fmt.Sprintf("%p", sc) - - for i := 0; i < 100; i++ { - - go func() { - <-proceed - sc := validate.extractStructCache(current, name) - Equal(t, ptr, fmt.Sprintf("%p", sc)) - }() - } - - close(proceed) -} - -// Thanks @robbrockbank, see https://github.com/go-playground/validator/issues/249 -func TestPointerAndOmitEmpty(t *testing.T) { - - type Test struct { - MyInt *int `validate:"omitempty,gte=2,lte=255"` - } - - val1 := 0 - val2 := 256 - - t1 := Test{MyInt: &val1} // This should fail validation on gte because value is 0 - t2 := Test{MyInt: &val2} // This should fail validate on lte because value is 256 - t3 := Test{MyInt: nil} // This should succeed validation because pointer is nil - - errs := validate.Struct(t1) - NotEqual(t, errs, nil) - AssertError(t, errs, "Test.MyInt", "MyInt", "gte") - - errs = validate.Struct(t2) - NotEqual(t, errs, nil) - AssertError(t, errs, "Test.MyInt", "MyInt", "lte") - - errs = validate.Struct(t3) - Equal(t, errs, nil) - - type TestIface struct { - MyInt interface{} `validate:"omitempty,gte=2,lte=255"` - } - - ti1 := TestIface{MyInt: &val1} // This should fail validation on gte because value is 0 - ti2 := TestIface{MyInt: &val2} // This should fail validate on lte because value is 256 - ti3 := TestIface{MyInt: nil} // This should succeed validation because pointer is nil - - errs = validate.Struct(ti1) - NotEqual(t, errs, nil) - AssertError(t, errs, "TestIface.MyInt", "MyInt", "gte") - - errs = validate.Struct(ti2) - NotEqual(t, errs, nil) - AssertError(t, errs, "TestIface.MyInt", "MyInt", "lte") - - errs = validate.Struct(ti3) - Equal(t, errs, nil) -} +// func TestStructUint64Validation(t *testing.T) { + +// tSuccess := &TestUint64{ +// Required: 1, +// Len: 10, +// Min: 1, +// Max: 10, +// MinMax: 5, +// OmitEmpty: 0, +// } + +// errs := validate.Struct(tSuccess) +// Equal(t, errs, nil) + +// tFail := &TestUint64{ +// Required: 0, +// Len: 11, +// Min: 0, +// Max: 11, +// MinMax: 0, +// OmitEmpty: 11, +// } + +// errs = validate.Struct(tFail) + +// // Assert Top Level +// NotEqual(t, errs, nil) +// Equal(t, len(errs.(ValidationErrors)), 6) + +// // Assert Fields +// AssertError(t, errs, "TestUint64.Required", "Required", "required") +// AssertError(t, errs, "TestUint64.Len", "Len", "len") +// AssertError(t, errs, "TestUint64.Min", "Min", "min") +// AssertError(t, errs, "TestUint64.Max", "Max", "max") +// AssertError(t, errs, "TestUint64.MinMax", "MinMax", "min") +// AssertError(t, errs, "TestUint64.OmitEmpty", "OmitEmpty", "max") +// } + +// func TestStructFloat64Validation(t *testing.T) { + +// tSuccess := &TestFloat64{ +// Required: 1, +// Len: 10, +// Min: 1, +// Max: 10, +// MinMax: 5, +// OmitEmpty: 0, +// } + +// errs := validate.Struct(tSuccess) +// Equal(t, errs, nil) + +// tFail := &TestFloat64{ +// Required: 0, +// Len: 11, +// Min: 0, +// Max: 11, +// MinMax: 0, +// OmitEmpty: 11, +// } + +// errs = validate.Struct(tFail) + +// // Assert Top Level +// NotEqual(t, errs, nil) +// Equal(t, len(errs.(ValidationErrors)), 6) + +// // Assert Fields +// AssertError(t, errs, "TestFloat64.Required", "Required", "required") +// AssertError(t, errs, "TestFloat64.Len", "Len", "len") +// AssertError(t, errs, "TestFloat64.Min", "Min", "min") +// AssertError(t, errs, "TestFloat64.Max", "Max", "max") +// AssertError(t, errs, "TestFloat64.MinMax", "MinMax", "min") +// AssertError(t, errs, "TestFloat64.OmitEmpty", "OmitEmpty", "max") +// } + +// func TestStructSliceValidation(t *testing.T) { + +// tSuccess := &TestSlice{ +// Required: []int{1}, +// Len: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}, +// Min: []int{1, 2}, +// Max: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}, +// MinMax: []int{1, 2, 3, 4, 5}, +// OmitEmpty: nil, +// } + +// errs := validate.Struct(tSuccess) +// Equal(t, errs, nil) + +// tFail := &TestSlice{ +// Required: nil, +// Len: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1}, +// Min: []int{}, +// Max: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1}, +// MinMax: []int{}, +// OmitEmpty: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1}, +// } + +// errs = validate.Struct(tFail) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.(ValidationErrors)), 6) + +// // Assert Field Errors +// AssertError(t, errs, "TestSlice.Required", "Required", "required") +// AssertError(t, errs, "TestSlice.Len", "Len", "len") +// AssertError(t, errs, "TestSlice.Min", "Min", "min") +// AssertError(t, errs, "TestSlice.Max", "Max", "max") +// AssertError(t, errs, "TestSlice.MinMax", "MinMax", "min") +// AssertError(t, errs, "TestSlice.OmitEmpty", "OmitEmpty", "max") +// } + +// func TestInvalidStruct(t *testing.T) { +// s := &SubTest{ +// Test: "1", +// } + +// PanicMatches(t, func() { validate.Struct(s.Test) }, "value passed for validation is not a struct") +// } + +// func TestInvalidValidatorFunction(t *testing.T) { +// s := &SubTest{ +// Test: "1", +// } + +// PanicMatches(t, func() { validate.Field(s.Test, "zzxxBadFunction") }, "Undefined validation function on field") +// } + +// func TestCustomFieldName(t *testing.T) { +// type A struct { +// B string `schema:"b" validate:"required"` +// C string `schema:"c" validate:"required"` +// D []bool `schema:"d" validate:"required"` +// E string `schema:"-" validate:"required"` +// } + +// a := &A{} + +// errs := New(&Config{TagName: "validate", FieldNameTag: "schema"}).Struct(a).(ValidationErrors) +// NotEqual(t, errs, nil) +// Equal(t, len(errs), 4) +// Equal(t, errs["A.B"].Name, "b") +// Equal(t, errs["A.C"].Name, "c") +// Equal(t, errs["A.D"].Name, "d") +// Equal(t, errs["A.E"].Name, "E") + +// errs = New(&Config{TagName: "validate"}).Struct(a).(ValidationErrors) +// NotEqual(t, errs, nil) +// Equal(t, len(errs), 4) +// Equal(t, errs["A.B"].Name, "B") +// Equal(t, errs["A.C"].Name, "C") +// Equal(t, errs["A.D"].Name, "D") +// Equal(t, errs["A.E"].Name, "E") +// } + +// func TestMutipleRecursiveExtractStructCache(t *testing.T) { + +// type Recursive struct { +// Field *string `validate:"exists,required,len=5,ne=string"` +// } + +// var test Recursive + +// current := reflect.ValueOf(test) +// name := "Recursive" +// proceed := make(chan struct{}) + +// sc := validate.extractStructCache(current, name) +// ptr := fmt.Sprintf("%p", sc) + +// for i := 0; i < 100; i++ { + +// go func() { +// <-proceed +// sc := validate.extractStructCache(current, name) +// Equal(t, ptr, fmt.Sprintf("%p", sc)) +// }() +// } + +// close(proceed) +// } + +// // Thanks @robbrockbank, see https://github.com/go-playground/validator/issues/249 +// func TestPointerAndOmitEmpty(t *testing.T) { + +// type Test struct { +// MyInt *int `validate:"omitempty,gte=2,lte=255"` +// } + +// val1 := 0 +// val2 := 256 + +// t1 := Test{MyInt: &val1} // This should fail validation on gte because value is 0 +// t2 := Test{MyInt: &val2} // This should fail validate on lte because value is 256 +// t3 := Test{MyInt: nil} // This should succeed validation because pointer is nil + +// errs := validate.Struct(t1) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "Test.MyInt", "MyInt", "gte") + +// errs = validate.Struct(t2) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "Test.MyInt", "MyInt", "lte") + +// errs = validate.Struct(t3) +// Equal(t, errs, nil) + +// type TestIface struct { +// MyInt interface{} `validate:"omitempty,gte=2,lte=255"` +// } + +// ti1 := TestIface{MyInt: &val1} // This should fail validation on gte because value is 0 +// ti2 := TestIface{MyInt: &val2} // This should fail validate on lte because value is 256 +// ti3 := TestIface{MyInt: nil} // This should succeed validation because pointer is nil + +// errs = validate.Struct(ti1) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "TestIface.MyInt", "MyInt", "gte") + +// errs = validate.Struct(ti2) +// NotEqual(t, errs, nil) +// AssertError(t, errs, "TestIface.MyInt", "MyInt", "lte") + +// errs = validate.Struct(ti3) +// Equal(t, errs, nil) +// }