Fix time.Duration parsing for int param (#678)

This fixes an issue where if the param of a time.Durtion type is specified
as an integer, denoting nanosecond precision, instead of time duration
string the validation would panic.

the fixes ensures it falls back to the previous expected behaviour.
pull/668/merge v10.4.1
Dean Karn 4 years ago committed by GitHub
parent d6b17fd90b
commit 456221b630
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      README.md
  2. 244
      baked_in.go
  3. 7
      util.go
  4. 47
      validator_test.go

@ -1,7 +1,7 @@
Package validator
================
<img align="right" src="https://raw.githubusercontent.com/go-playground/validator/v9/logo.png">[![Join the chat at https://gitter.im/go-playground/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-10.3.0-green.svg)
![Project status](https://img.shields.io/badge/version-10.4.1-green.svg)
[![Build Status](https://travis-ci.org/go-playground/validator.svg?branch=master)](https://travis-ci.org/go-playground/validator)
[![Coverage Status](https://coveralls.io/repos/go-playground/validator/badge.svg?branch=master&service=github)](https://coveralls.io/github/go-playground/validator?branch=master)
[![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/validator)](https://goreportcard.com/report/github.com/go-playground/validator)

@ -67,125 +67,125 @@ 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,
"required_if": requiredIf,
"required_unless": requiredUnless,
"required_with": requiredWith,
"required_with_all": requiredWithAll,
"required_without": requiredWithout,
"required_without_all": requiredWithoutAll,
"excluded_with": excludedWith,
"excluded_with_all": excludedWithAll,
"excluded_without": excludedWithout,
"excluded_without_all": excludedWithoutAll,
"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,
"fieldcontains": fieldContains,
"fieldexcludes": fieldExcludes,
"alpha": isAlpha,
"alphanum": isAlphanum,
"alphaunicode": isAlphaUnicode,
"alphanumunicode": isAlphanumUnicode,
"numeric": isNumeric,
"number": isNumber,
"hexadecimal": isHexadecimal,
"hexcolor": isHEXColor,
"rgb": isRGB,
"rgba": isRGBA,
"hsl": isHSL,
"hsla": isHSLA,
"e164": isE164,
"email": isEmail,
"url": isURL,
"uri": isURI,
"urn_rfc2141": isUrnRFC2141, // RFC 2141
"file": isFile,
"base64": isBase64,
"base64url": isBase64URL,
"contains": contains,
"containsany": containsAny,
"containsrune": containsRune,
"excludes": excludes,
"excludesall": excludesAll,
"excludesrune": excludesRune,
"startswith": startsWith,
"endswith": endsWith,
"startsnotwith": startsNotWith,
"endsnotwith": endsNotWith,
"isbn": isISBN,
"isbn10": isISBN10,
"isbn13": isISBN13,
"eth_addr": isEthereumAddress,
"btc_addr": isBitcoinAddress,
"btc_addr_bech32": isBitcoinBech32Address,
"uuid": isUUID,
"uuid3": isUUID3,
"uuid4": isUUID4,
"uuid5": isUUID5,
"uuid_rfc4122": isUUIDRFC4122,
"uuid3_rfc4122": isUUID3RFC4122,
"uuid4_rfc4122": isUUID4RFC4122,
"uuid5_rfc4122": isUUID5RFC4122,
"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,
"oneof": isOneOf,
"html": isHTML,
"html_encoded": isHTMLEncoded,
"url_encoded": isURLEncoded,
"dir": isDir,
"json": isJSON,
"hostname_port": isHostnamePort,
"lowercase": isLowercase,
"uppercase": isUppercase,
"datetime": isDatetime,
"timezone": isTimeZone,
"iso3166_1_alpha2": isIso3166Alpha2,
"required": hasValue,
"required_if": requiredIf,
"required_unless": requiredUnless,
"required_with": requiredWith,
"required_with_all": requiredWithAll,
"required_without": requiredWithout,
"required_without_all": requiredWithoutAll,
"excluded_with": excludedWith,
"excluded_with_all": excludedWithAll,
"excluded_without": excludedWithout,
"excluded_without_all": excludedWithoutAll,
"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,
"fieldcontains": fieldContains,
"fieldexcludes": fieldExcludes,
"alpha": isAlpha,
"alphanum": isAlphanum,
"alphaunicode": isAlphaUnicode,
"alphanumunicode": isAlphanumUnicode,
"numeric": isNumeric,
"number": isNumber,
"hexadecimal": isHexadecimal,
"hexcolor": isHEXColor,
"rgb": isRGB,
"rgba": isRGBA,
"hsl": isHSL,
"hsla": isHSLA,
"e164": isE164,
"email": isEmail,
"url": isURL,
"uri": isURI,
"urn_rfc2141": isUrnRFC2141, // RFC 2141
"file": isFile,
"base64": isBase64,
"base64url": isBase64URL,
"contains": contains,
"containsany": containsAny,
"containsrune": containsRune,
"excludes": excludes,
"excludesall": excludesAll,
"excludesrune": excludesRune,
"startswith": startsWith,
"endswith": endsWith,
"startsnotwith": startsNotWith,
"endsnotwith": endsNotWith,
"isbn": isISBN,
"isbn10": isISBN10,
"isbn13": isISBN13,
"eth_addr": isEthereumAddress,
"btc_addr": isBitcoinAddress,
"btc_addr_bech32": isBitcoinBech32Address,
"uuid": isUUID,
"uuid3": isUUID3,
"uuid4": isUUID4,
"uuid5": isUUID5,
"uuid_rfc4122": isUUIDRFC4122,
"uuid3_rfc4122": isUUID3RFC4122,
"uuid4_rfc4122": isUUID4RFC4122,
"uuid5_rfc4122": isUUID5RFC4122,
"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,
"oneof": isOneOf,
"html": isHTML,
"html_encoded": isHTMLEncoded,
"url_encoded": isURLEncoded,
"dir": isDir,
"json": isJSON,
"hostname_port": isHostnamePort,
"lowercase": isLowercase,
"uppercase": isUppercase,
"datetime": isDatetime,
"timezone": isTimeZone,
"iso3166_1_alpha2": isIso3166Alpha2,
"iso3166_1_alpha3": isIso3166Alpha3,
"iso3166_1_alpha_numeric": isIso3166AlphaNumeric,
}
@ -2250,11 +2250,7 @@ func isTimeZone(fl FieldLevel) bool {
}
_, err := time.LoadLocation(field.String())
if err != nil {
return false
}
return true
return err == nil
}
panic(fmt.Sprintf("Bad field type %T", field.Interface()))

@ -223,7 +223,6 @@ BEGIN:
// asInt returns the parameter as a int64
// or panics if it can't convert
func asInt(param string) int64 {
i, err := strconv.ParseInt(param, 0, 64)
panicIf(err)
@ -234,8 +233,10 @@ func asInt(param string) int64 {
// or panics on error.
func asIntFromTimeDuration(param string) int64 {
d, err := time.ParseDuration(param)
panicIf(err)
if err != nil {
// attempt parsing as an an integer assuming nanosecond precision
return asInt(param)
}
return int64(d)
}

@ -9475,7 +9475,7 @@ func TestUniqueValidationStructPtrSlice(t *testing.T) {
}
}
}
PanicMatches(t, func() { validate.Var(testStructs, "unique=C") }, "Bad field name C")
PanicMatches(t, func() { _ = validate.Var(testStructs, "unique=C") }, "Bad field name C")
}
func TestHTMLValidation(t *testing.T) {
@ -10989,4 +10989,47 @@ func TestTimeZoneValidation(t *testing.T) {
PanicMatches(t, func() {
_ = validate.Var(2, "timezone")
}, "Bad field type int")
}
}
func TestDurationType(t *testing.T) {
tests := []struct {
name string
s interface{} // struct
success bool
}{
{
name: "valid duration string pass",
s: struct {
Value time.Duration `validate:"gte=500ns"`
}{
Value: time.Second,
},
success: true,
},
{
name: "valid duration int pass",
s: struct {
Value time.Duration `validate:"gte=500"`
}{
Value: time.Second,
},
success: true,
},
}
validate := New()
for _, tc := range tests {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
errs := validate.Struct(tc.s)
if tc.success {
Equal(t, errs, nil)
return
}
NotEqual(t, errs, nil)
})
}
}

Loading…
Cancel
Save