Add hostname_rfc1123 validation

pull/343/head
Dean Karn 7 years ago
parent 3620d3c069
commit 5e036656b8
  1. 126
      README.md
  2. 171
      baked_in.go
  3. 4
      cache.go
  4. 10
      doc.go
  5. 6
      regexes.go
  6. 2
      util.go
  7. 28
      validator.go
  8. 44
      validator_instance.go
  9. 131
      validator_test.go

@ -66,69 +66,71 @@ Please see http://godoc.org/gopkg.in/go-playground/validator.v9 for detailed usa
Benchmarks
------
###### Run on MacBook Pro (15-inch, 2017) Go version go1.9.2 darwin/amd64
###### Run on MacBook Pro (15-inch, 2017) Go version go1.9.4 darwin/amd64
```go
go test -bench=. -benchmem=true
BenchmarkFieldSuccess-8 20000000 79.9 ns/op 0 B/op 0 allocs/op
BenchmarkFieldSuccessParallel-8 50000000 25.0 ns/op 0 B/op 0 allocs/op
BenchmarkFieldFailure-8 5000000 281 ns/op 208 B/op 4 allocs/op
BenchmarkFieldFailureParallel-8 20000000 97.0 ns/op 208 B/op 4 allocs/op
BenchmarkFieldArrayDiveSuccess-8 3000000 591 ns/op 201 B/op 11 allocs/op
BenchmarkFieldArrayDiveSuccessParallel-8 10000000 195 ns/op 201 B/op 11 allocs/op
BenchmarkFieldArrayDiveFailure-8 2000000 878 ns/op 412 B/op 16 allocs/op
BenchmarkFieldArrayDiveFailureParallel-8 5000000 274 ns/op 413 B/op 16 allocs/op
BenchmarkFieldMapDiveSuccess-8 1000000 1279 ns/op 432 B/op 18 allocs/op
BenchmarkFieldMapDiveSuccessParallel-8 5000000 401 ns/op 432 B/op 18 allocs/op
BenchmarkFieldMapDiveFailure-8 1000000 1060 ns/op 512 B/op 16 allocs/op
BenchmarkFieldMapDiveFailureParallel-8 5000000 334 ns/op 512 B/op 16 allocs/op
BenchmarkFieldMapDiveWithKeysSuccess-8 1000000 1462 ns/op 480 B/op 21 allocs/op
BenchmarkFieldMapDiveWithKeysSuccessParallel-8 3000000 463 ns/op 480 B/op 21 allocs/op
BenchmarkFieldMapDiveWithKeysFailure-8 1000000 1414 ns/op 721 B/op 21 allocs/op
BenchmarkFieldMapDiveWithKeysFailureParallel-8 3000000 446 ns/op 721 B/op 21 allocs/op
BenchmarkFieldCustomTypeSuccess-8 10000000 211 ns/op 32 B/op 2 allocs/op
BenchmarkFieldCustomTypeSuccessParallel-8 20000000 65.9 ns/op 32 B/op 2 allocs/op
BenchmarkFieldCustomTypeFailure-8 5000000 270 ns/op 208 B/op 4 allocs/op
BenchmarkFieldCustomTypeFailureParallel-8 20000000 93.3 ns/op 208 B/op 4 allocs/op
BenchmarkFieldOrTagSuccess-8 2000000 729 ns/op 16 B/op 1 allocs/op
BenchmarkFieldOrTagSuccessParallel-8 5000000 367 ns/op 16 B/op 1 allocs/op
BenchmarkFieldOrTagFailure-8 3000000 472 ns/op 224 B/op 5 allocs/op
BenchmarkFieldOrTagFailureParallel-8 5000000 373 ns/op 224 B/op 5 allocs/op
BenchmarkStructLevelValidationSuccess-8 10000000 201 ns/op 32 B/op 2 allocs/op
BenchmarkStructLevelValidationSuccessParallel-8 20000000 66.3 ns/op 32 B/op 2 allocs/op
BenchmarkStructLevelValidationFailure-8 3000000 468 ns/op 304 B/op 8 allocs/op
BenchmarkStructLevelValidationFailureParallel-8 10000000 172 ns/op 304 B/op 8 allocs/op
BenchmarkStructSimpleCustomTypeSuccess-8 5000000 376 ns/op 32 B/op 2 allocs/op
BenchmarkStructSimpleCustomTypeSuccessParallel-8 20000000 126 ns/op 32 B/op 2 allocs/op
BenchmarkStructSimpleCustomTypeFailure-8 2000000 646 ns/op 424 B/op 9 allocs/op
BenchmarkStructSimpleCustomTypeFailureParallel-8 10000000 240 ns/op 440 B/op 10 allocs/op
BenchmarkStructFilteredSuccess-8 3000000 582 ns/op 288 B/op 9 allocs/op
BenchmarkStructFilteredSuccessParallel-8 10000000 198 ns/op 288 B/op 9 allocs/op
BenchmarkStructFilteredFailure-8 3000000 447 ns/op 256 B/op 7 allocs/op
BenchmarkStructFilteredFailureParallel-8 10000000 156 ns/op 256 B/op 7 allocs/op
BenchmarkStructPartialSuccess-8 3000000 536 ns/op 256 B/op 6 allocs/op
BenchmarkStructPartialSuccessParallel-8 10000000 175 ns/op 256 B/op 6 allocs/op
BenchmarkStructPartialFailure-8 2000000 738 ns/op 480 B/op 11 allocs/op
BenchmarkStructPartialFailureParallel-8 5000000 256 ns/op 480 B/op 11 allocs/op
BenchmarkStructExceptSuccess-8 2000000 835 ns/op 496 B/op 12 allocs/op
BenchmarkStructExceptSuccessParallel-8 10000000 163 ns/op 240 B/op 5 allocs/op
BenchmarkStructExceptFailure-8 2000000 682 ns/op 464 B/op 10 allocs/op
BenchmarkStructExceptFailureParallel-8 10000000 244 ns/op 464 B/op 10 allocs/op
BenchmarkStructSimpleCrossFieldSuccess-8 5000000 392 ns/op 72 B/op 3 allocs/op
BenchmarkStructSimpleCrossFieldSuccessParallel-8 20000000 126 ns/op 72 B/op 3 allocs/op
BenchmarkStructSimpleCrossFieldFailure-8 2000000 611 ns/op 304 B/op 8 allocs/op
BenchmarkStructSimpleCrossFieldFailureParallel-8 10000000 214 ns/op 304 B/op 8 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 3000000 567 ns/op 80 B/op 4 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldSuccessParallel-8 10000000 177 ns/op 80 B/op 4 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldFailure-8 2000000 807 ns/op 320 B/op 9 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldFailureParallel-8 5000000 268 ns/op 320 B/op 9 allocs/op
BenchmarkStructSimpleSuccess-8 5000000 256 ns/op 0 B/op 0 allocs/op
BenchmarkStructSimpleSuccessParallel-8 20000000 76.3 ns/op 0 B/op 0 allocs/op
BenchmarkStructSimpleFailure-8 2000000 625 ns/op 424 B/op 9 allocs/op
BenchmarkStructSimpleFailureParallel-8 10000000 219 ns/op 424 B/op 9 allocs/op
BenchmarkStructComplexSuccess-8 1000000 1431 ns/op 128 B/op 8 allocs/op
BenchmarkStructComplexSuccessParallel-8 3000000 427 ns/op 128 B/op 8 allocs/op
BenchmarkStructComplexFailure-8 300000 4065 ns/op 3041 B/op 53 allocs/op
BenchmarkStructComplexFailureParallel-8 1000000 1478 ns/op 3041 B/op 53 allocs/op
goos: darwin
goarch: amd64
pkg: github.com/go-playground/validator
BenchmarkFieldSuccess-8 20000000 86.4 ns/op 0 B/op 0 allocs/op
BenchmarkFieldSuccessParallel-8 50000000 27.6 ns/op 0 B/op 0 allocs/op
BenchmarkFieldFailure-8 5000000 297 ns/op 208 B/op 4 allocs/op
BenchmarkFieldFailureParallel-8 20000000 107 ns/op 208 B/op 4 allocs/op
BenchmarkFieldArrayDiveSuccess-8 2000000 618 ns/op 201 B/op 11 allocs/op
BenchmarkFieldArrayDiveSuccessParallel-8 10000000 225 ns/op 201 B/op 11 allocs/op
BenchmarkFieldArrayDiveFailure-8 2000000 863 ns/op 412 B/op 16 allocs/op
BenchmarkFieldArrayDiveFailureParallel-8 5000000 322 ns/op 413 B/op 16 allocs/op
BenchmarkFieldMapDiveSuccess-8 1000000 1336 ns/op 432 B/op 18 allocs/op
BenchmarkFieldMapDiveSuccessParallel-8 3000000 474 ns/op 432 B/op 18 allocs/op
BenchmarkFieldMapDiveFailure-8 1000000 1103 ns/op 512 B/op 16 allocs/op
BenchmarkFieldMapDiveFailureParallel-8 5000000 412 ns/op 512 B/op 16 allocs/op
BenchmarkFieldMapDiveWithKeysSuccess-8 1000000 1572 ns/op 480 B/op 21 allocs/op
BenchmarkFieldMapDiveWithKeysSuccessParallel-8 3000000 615 ns/op 480 B/op 21 allocs/op
BenchmarkFieldMapDiveWithKeysFailure-8 1000000 1438 ns/op 721 B/op 21 allocs/op
BenchmarkFieldMapDiveWithKeysFailureParallel-8 3000000 543 ns/op 721 B/op 21 allocs/op
BenchmarkFieldCustomTypeSuccess-8 10000000 230 ns/op 32 B/op 2 allocs/op
BenchmarkFieldCustomTypeSuccessParallel-8 20000000 82.5 ns/op 32 B/op 2 allocs/op
BenchmarkFieldCustomTypeFailure-8 5000000 284 ns/op 208 B/op 4 allocs/op
BenchmarkFieldCustomTypeFailureParallel-8 20000000 118 ns/op 208 B/op 4 allocs/op
BenchmarkFieldOrTagSuccess-8 2000000 824 ns/op 16 B/op 1 allocs/op
BenchmarkFieldOrTagSuccessParallel-8 3000000 472 ns/op 16 B/op 1 allocs/op
BenchmarkFieldOrTagFailure-8 3000000 487 ns/op 224 B/op 5 allocs/op
BenchmarkFieldOrTagFailureParallel-8 5000000 405 ns/op 224 B/op 5 allocs/op
BenchmarkStructLevelValidationSuccess-8 10000000 214 ns/op 32 B/op 2 allocs/op
BenchmarkStructLevelValidationSuccessParallel-8 20000000 78.0 ns/op 32 B/op 2 allocs/op
BenchmarkStructLevelValidationFailure-8 3000000 475 ns/op 304 B/op 8 allocs/op
BenchmarkStructLevelValidationFailureParallel-8 10000000 200 ns/op 304 B/op 8 allocs/op
BenchmarkStructSimpleCustomTypeSuccess-8 3000000 403 ns/op 32 B/op 2 allocs/op
BenchmarkStructSimpleCustomTypeSuccessParallel-8 10000000 143 ns/op 32 B/op 2 allocs/op
BenchmarkStructSimpleCustomTypeFailure-8 2000000 655 ns/op 424 B/op 9 allocs/op
BenchmarkStructSimpleCustomTypeFailureParallel-8 5000000 286 ns/op 440 B/op 10 allocs/op
BenchmarkStructFilteredSuccess-8 2000000 598 ns/op 288 B/op 9 allocs/op
BenchmarkStructFilteredSuccessParallel-8 10000000 231 ns/op 288 B/op 9 allocs/op
BenchmarkStructFilteredFailure-8 3000000 455 ns/op 256 B/op 7 allocs/op
BenchmarkStructFilteredFailureParallel-8 10000000 197 ns/op 256 B/op 7 allocs/op
BenchmarkStructPartialSuccess-8 3000000 552 ns/op 256 B/op 6 allocs/op
BenchmarkStructPartialSuccessParallel-8 10000000 206 ns/op 256 B/op 6 allocs/op
BenchmarkStructPartialFailure-8 2000000 750 ns/op 480 B/op 11 allocs/op
BenchmarkStructPartialFailureParallel-8 5000000 317 ns/op 480 B/op 11 allocs/op
BenchmarkStructExceptSuccess-8 2000000 853 ns/op 496 B/op 12 allocs/op
BenchmarkStructExceptSuccessParallel-8 10000000 179 ns/op 240 B/op 5 allocs/op
BenchmarkStructExceptFailure-8 2000000 698 ns/op 464 B/op 10 allocs/op
BenchmarkStructExceptFailureParallel-8 5000000 276 ns/op 464 B/op 10 allocs/op
BenchmarkStructSimpleCrossFieldSuccess-8 3000000 412 ns/op 72 B/op 3 allocs/op
BenchmarkStructSimpleCrossFieldSuccessParallel-8 10000000 148 ns/op 72 B/op 3 allocs/op
BenchmarkStructSimpleCrossFieldFailure-8 2000000 630 ns/op 304 B/op 8 allocs/op
BenchmarkStructSimpleCrossFieldFailureParallel-8 10000000 244 ns/op 304 B/op 8 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 2000000 610 ns/op 80 B/op 4 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldSuccessParallel-8 10000000 205 ns/op 80 B/op 4 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldFailure-8 2000000 861 ns/op 320 B/op 9 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldFailureParallel-8 5000000 315 ns/op 320 B/op 9 allocs/op
BenchmarkStructSimpleSuccess-8 5000000 279 ns/op 0 B/op 0 allocs/op
BenchmarkStructSimpleSuccessParallel-8 20000000 86.4 ns/op 0 B/op 0 allocs/op
BenchmarkStructSimpleFailure-8 2000000 636 ns/op 424 B/op 9 allocs/op
BenchmarkStructSimpleFailureParallel-8 10000000 264 ns/op 424 B/op 9 allocs/op
BenchmarkStructComplexSuccess-8 1000000 1539 ns/op 128 B/op 8 allocs/op
BenchmarkStructComplexSuccessParallel-8 3000000 557 ns/op 128 B/op 8 allocs/op
BenchmarkStructComplexFailure-8 300000 4136 ns/op 3041 B/op 53 allocs/op
BenchmarkStructComplexFailureParallel-8 1000000 1855 ns/op 3041 B/op 53 allocs/op
```
Complementary Software

@ -55,85 +55,86 @@ var (
// 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,
"isdefault": isDefault,
"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,
"alphaunicode": isAlphaUnicode,
"alphanumunicode": isAlphanumUnicode,
"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,
"hostname": isHostname,
"fqdn": isFQDN,
"unique": isUnique,
"required": hasValue,
"isdefault": isDefault,
"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,
"alphaunicode": isAlphaUnicode,
"alphanumunicode": isAlphanumUnicode,
"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,
"hostname": isHostnameRFC952, // RFC 952
"hostname_rfc1123": isHostnameRFC1123, // RFC 1123
"fqdn": isFQDN,
"unique": isUnique,
}
)
@ -1511,8 +1512,12 @@ func isIP6Addr(fl FieldLevel) bool {
return ip != nil && ip.To4() == nil
}
func isHostname(fl FieldLevel) bool {
return hostnameRegex.MatchString(fl.Field().String())
func isHostnameRFC952(fl FieldLevel) bool {
return hostnameRegexRFC952.MatchString(fl.Field().String())
}
func isHostnameRFC1123(fl FieldLevel) bool {
return hostnameRegexRFC1123.MatchString(fl.Field().String())
}
func isFQDN(fl FieldLevel) bool {
@ -1526,6 +1531,6 @@ func isFQDN(fl FieldLevel) bool {
val = val[0 : len(val)-1]
}
return (strings.IndexAny(val, ".") > -1) &&
hostnameRegex.MatchString(val)
return strings.ContainsAny(val, ".") &&
hostnameRegexRFC952.MatchString(val)
}

@ -91,14 +91,14 @@ type cTag struct {
aliasTag string
actualAliasTag string
param string
typeof tagType
keys *cTag // only populated when using tag's 'keys' and 'endkeys' for map key validation
next *cTag
fn FuncCtx
typeof tagType
hasTag bool
hasAlias bool
hasParam bool // true if parameter used eg. eq= where the equal sign has been set
isBlockEnd bool // indicates the current tag represents the last validation in the block
fn FuncCtx
}
func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStruct {

@ -832,12 +832,18 @@ Note: See Go's ParseMAC for accepted formats and types:
http://golang.org/src/net/mac.go?s=866:918#L29
Hostname
Hostname RFC 952
This validates that a string value is a valid Hostname
This validates that a string value is a valid Hostname according to RFC 952 https://tools.ietf.org/html/rfc952
Usage: hostname
Hostname RFC 1123
This validates that a string value is a valid Hostname according to RFC 1123 https://tools.ietf.org/html/rfc1123
Usage: hostname_rfc1123 or if you want to continue to use 'hostname' in your tags, create an alias.
Full Qualified Domain Name (FQDN)
This validates that a string value contains a valid FQDN.

@ -30,7 +30,8 @@ const (
latitudeRegexString = "^[-+]?([1-8]?\\d(\\.\\d+)?|90(\\.0+)?)$"
longitudeRegexString = "^[-+]?(180(\\.0+)?|((1[0-7]\\d)|([1-9]?\\d))(\\.\\d+)?)$"
sSNRegexString = `^\d{3}[- ]?\d{2}[- ]?\d{4}$`
hostnameRegexString = `^[a-zA-Z][a-zA-Z0-9\-\.]+[a-z-Az0-9]$`
hostnameRegexStringRFC952 = `^[a-zA-Z][a-zA-Z0-9\-\.]+[a-z-Az0-9]$` // https://tools.ietf.org/html/rfc952
hostnameRegexStringRFC1123 = `^[a-zA-Z0-9][a-zA-Z0-9\-\.]+[a-z-Az0-9]$` // accepts hostname starting with a digit https://tools.ietf.org/html/rfc1123
)
var (
@ -61,5 +62,6 @@ var (
latitudeRegex = regexp.MustCompile(latitudeRegexString)
longitudeRegex = regexp.MustCompile(longitudeRegexString)
sSNRegex = regexp.MustCompile(sSNRegexString)
hostnameRegex = regexp.MustCompile(hostnameRegexString)
hostnameRegexRFC952 = regexp.MustCompile(hostnameRegexStringRFC952)
hostnameRegexRFC1123 = regexp.MustCompile(hostnameRegexStringRFC1123)
)

@ -80,7 +80,7 @@ BEGIN:
typ := current.Type()
fld := namespace
ns := namespace
var ns string
if typ != timeType {

@ -14,24 +14,19 @@ type validate struct {
ns []byte
actualNs []byte
errs ValidationErrors
includeExclude map[string]struct{} // reset only if StructPartial or StructExcept are called, no need otherwise
ffn FilterFunc
slflParent reflect.Value // StructLevel & FieldLevel
slCurrent reflect.Value // StructLevel & FieldLevel
flField reflect.Value // StructLevel & FieldLevel
cf *cField // StructLevel & FieldLevel
ct *cTag // StructLevel & FieldLevel
misc []byte // misc reusable
str1 string // misc reusable
str2 string // misc reusable
fldIsPointer bool // StructLevel & FieldLevel
isPartial bool
hasExcludes bool
includeExclude map[string]struct{} // reset only if StructPartial or StructExcept are called, no need otherwise
ffn FilterFunc
// StructLevel & FieldLevel fields
slflParent reflect.Value
slCurrent reflect.Value
flField reflect.Value
fldIsPointer bool
cf *cField
ct *cTag
// misc reusable values
misc []byte
str1 string
str2 string
}
// parent and current will be the same the first run of validateStruct
@ -127,7 +122,6 @@ func (v *validate) traverseField(ctx context.Context, parent reflect.Value, curr
}
if kind == reflect.Invalid {
v.errs = append(v.errs,
&fieldError{
v: v.v,

@ -370,39 +370,37 @@ func (v *Validate) StructPartialCtx(ctx context.Context, s interface{}, fields .
typ := val.Type()
name := typ.Name()
if fields != nil {
for _, k := range fields {
for _, k := range fields {
flds := strings.Split(k, namespaceSeparator)
if len(flds) > 0 {
flds := strings.Split(k, namespaceSeparator)
if len(flds) > 0 {
vd.misc = append(vd.misc[0:0], name...)
vd.misc = append(vd.misc, '.')
for _, s := range flds {
vd.misc = append(vd.misc[0:0], name...)
vd.misc = append(vd.misc, '.')
idx := strings.Index(s, leftBracket)
for _, s := range flds {
if idx != -1 {
for idx != -1 {
vd.misc = append(vd.misc, s[:idx]...)
vd.includeExclude[string(vd.misc)] = struct{}{}
idx := strings.Index(s, leftBracket)
idx2 := strings.Index(s, rightBracket)
idx2++
vd.misc = append(vd.misc, s[idx:idx2]...)
vd.includeExclude[string(vd.misc)] = struct{}{}
s = s[idx2:]
idx = strings.Index(s, leftBracket)
}
} else {
if idx != -1 {
for idx != -1 {
vd.misc = append(vd.misc, s[:idx]...)
vd.includeExclude[string(vd.misc)] = struct{}{}
vd.misc = append(vd.misc, s...)
idx2 := strings.Index(s, rightBracket)
idx2++
vd.misc = append(vd.misc, s[idx:idx2]...)
vd.includeExclude[string(vd.misc)] = struct{}{}
s = s[idx2:]
idx = strings.Index(s, leftBracket)
}
} else {
vd.misc = append(vd.misc, '.')
vd.misc = append(vd.misc, s...)
vd.includeExclude[string(vd.misc)] = struct{}{}
}
vd.misc = append(vd.misc, '.')
}
}
}

@ -1564,10 +1564,6 @@ func TestCrossNamespaceFieldValidation(t *testing.T) {
Name string
}
type MapStruct struct {
Name string
}
type Inner struct {
CreatedAt *time.Time
Slice []string
@ -1653,10 +1649,10 @@ func TestCrossNamespaceFieldValidation(t *testing.T) {
Equal(t, kind, reflect.String)
Equal(t, current.String(), "val2")
current, kind, ok = v.getStructFieldOKInternal(val, "Inner.CrazyNonExistantField")
current, _, ok = v.getStructFieldOKInternal(val, "Inner.CrazyNonExistantField")
Equal(t, ok, false)
current, kind, ok = v.getStructFieldOKInternal(val, "Inner.Slice[101]")
current, _, ok = v.getStructFieldOKInternal(val, "Inner.Slice[101]")
Equal(t, ok, false)
current, kind, ok = v.getStructFieldOKInternal(val, "Inner.Map[key3]")
@ -1854,8 +1850,6 @@ func TestSQLValue2Validation(t *testing.T) {
PanicMatches(t, func() { validate.Var(val, "required") }, "SQL Driver Valuer error: some kind of error")
type myValuer valuer
myVal := valuer{
Name: "",
}
@ -1907,8 +1901,6 @@ func TestSQLValueValidation(t *testing.T) {
PanicMatches(t, func() { errs = validate.Var(val, "required") }, "SQL Driver Valuer error: some kind of error")
type myValuer valuer
myVal := valuer{
Name: "",
}
@ -2696,11 +2688,8 @@ func TestBadKeyValidation(t *testing.T) {
func TestInterfaceErrValidation(t *testing.T) {
var v1 interface{}
var v2 interface{}
v2 = 1
v1 = v2
var v2 interface{} = 1
var v1 interface{} = v2
validate := New()
errs := validate.Var(v1, "len=1")
@ -7146,7 +7135,7 @@ func TestValidateStructRegisterCtx(t *testing.T) {
Equal(t, ctxSlVal, "slVal")
}
func TestHostnameValidation(t *testing.T) {
func TestHostnameRFC952Validation(t *testing.T) {
tests := []struct {
param string
expected bool
@ -7157,6 +7146,7 @@ func TestHostnameValidation(t *testing.T) {
{"test.example24.com", true},
{"test24.example24.com", true},
{"example", true},
{"1.foo.com", false},
{"test.example.com.", false},
{"example.com.", false},
{"example24.com.", false},
@ -7178,15 +7168,112 @@ func TestHostnameValidation(t *testing.T) {
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d hostname failed Error: %s", i, errs)
t.Fatalf("Index: %d hostname failed Error: %v", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d hostname failed Error: %v", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "hostname" {
t.Fatalf("Index: %d hostname failed Error: %v", i, errs)
}
}
}
}
}
func TestHostnameRFC1123Validation(t *testing.T) {
tests := []struct {
param string
expected bool
}{
{"test.example.com", true},
{"example.com", true},
{"example24.com", true},
{"test.example24.com", true},
{"test24.example24.com", true},
{"example", true},
{"1.foo.com", true},
{"test.example.com.", false},
{"example.com.", false},
{"example24.com.", false},
{"test.example24.com.", false},
{"test24.example24.com.", false},
{"example.", false},
{"192.168.0.1", true},
{"email@example.com", false},
{"2001:cdba:0000:0000:0000:0000:3257:9652", false},
{"2001:cdba:0:0:0:0:3257:9652", false},
{"2001:cdba::3257:9652", false},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "hostname_rfc1123")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d hostname failed Error: %v", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d hostname failed Error: %v", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "hostname_rfc1123" {
t.Fatalf("Index: %d hostname failed Error: %v", i, errs)
}
}
}
}
}
func TestHostnameRFC1123AliasValidation(t *testing.T) {
tests := []struct {
param string
expected bool
}{
{"test.example.com", true},
{"example.com", true},
{"example24.com", true},
{"test.example24.com", true},
{"test24.example24.com", true},
{"example", true},
{"1.foo.com", true},
{"test.example.com.", false},
{"example.com.", false},
{"example24.com.", false},
{"test.example24.com.", false},
{"test24.example24.com.", false},
{"example.", false},
{"192.168.0.1", true},
{"email@example.com", false},
{"2001:cdba:0000:0000:0000:0000:3257:9652", false},
{"2001:cdba:0:0:0:0:3257:9652", false},
{"2001:cdba::3257:9652", false},
}
validate := New()
validate.RegisterAlias("hostname", "hostname_rfc1123")
for i, test := range tests {
errs := validate.Var(test.param, "hostname")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d hostname failed Error: %v", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d hostname failed Error: %s", i, errs)
t.Fatalf("Index: %d hostname failed Error: %v", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "hostname" {
t.Fatalf("Index: %d hostname failed Error: %s", i, errs)
t.Fatalf("Index: %d hostname failed Error: %v", i, errs)
}
}
}
@ -7226,15 +7313,15 @@ func TestFQDNValidation(t *testing.T) {
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d fqdn failed Error: %s", i, errs)
t.Fatalf("Index: %d fqdn failed Error: %v", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d fqdn failed Error: %s", i, errs)
t.Fatalf("Index: %d fqdn failed Error: %v", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "fqdn" {
t.Fatalf("Index: %d fqdn failed Error: %s", i, errs)
t.Fatalf("Index: %d fqdn failed Error: %v", i, errs)
}
}
}

Loading…
Cancel
Save