Repository: go-playground/validator
Pull request #673 (2020-10-07 09:13:16)

Fix excludedWithoutAll comment
Fixes Or Enhances https://github.com/go-playground/validator/issues/660

**Make sure that you've checked the boxes below before you submit PR:**
- [x] Tests exist or have been written that cover this particular change.

Change Details:

- excludedWithoutAll function comment mistakenly referred to a different function

@go-playground/admins


Patch:
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index 6d3811c..7cad4db 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -2,7 +2,7 @@
 
 ## Quality Standard
 
-To ensure the continued stability of this package, tests are required to be written or already exist in order for a pull request to be merged.
+To ensure the continued stability of this package, tests are required that cover the change in order for a pull request to be merged.
 
 ## Reporting issues
 
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
index 8afb259..0104499 100644
--- a/.github/ISSUE_TEMPLATE.md
+++ b/.github/ISSUE_TEMPLATE.md
@@ -1,4 +1,4 @@
-### Package version eg. v8, v9: 
+### Package version eg. v9, v10: 
 
 
 
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 7bebde3..6bb0db3 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -1,13 +1,7 @@
-Fixes Or Enhances # .
+## Fixes Or Enhances
+
 
 **Make sure that you've checked the boxes below before you submit PR:**
 - [ ] Tests exist or have been written that cover this particular change.
 
-Change Details:
-
-- 
-- 
-- 
-
-
 @go-playground/admins
\ No newline at end of file
diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml
new file mode 100644
index 0000000..0025ea0
--- /dev/null
+++ b/.github/workflows/workflow.yml
@@ -0,0 +1,48 @@
+on:
+  push:
+    branches:
+      - master
+  pull_request:
+name: Test
+jobs:
+  test:
+    strategy:
+      matrix:
+        go-version: [1.14.x, 1.15.x]
+        os: [ubuntu-latest, macos-latest, windows-latest]
+    runs-on: ${{ matrix.os }}
+    steps:
+      - name: Install Go
+        uses: actions/setup-go@v2
+        with:
+          go-version: ${{ matrix.go-version }}
+
+      - name: Checkout code
+        uses: actions/checkout@v2
+
+      - name: Restore Cache
+        uses: actions/cache@v2
+        with:
+          path: ~/go/pkg/mod
+          key: ${{ runner.os }}-v1-go-${{ hashFiles('**/go.sum') }}
+          restore-keys: |
+            ${{ runner.os }}-v1-go-
+
+      - name: Test
+        run: go test -race -covermode=atomic -coverprofile="profile.cov" ./...
+
+      - name: Send Coverage
+        if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.15.x'
+        uses: shogo82148/actions-goveralls@v1
+        with:
+          path-to-profile: profile.cov
+
+  golangci:
+    name: lint
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v2
+      - name: golangci-lint
+        uses: golangci/golangci-lint-action@v2
+        with:
+          version: v1.31
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 85a7be3..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,29 +0,0 @@
-language: go
-go:
-  - 1.15.2
-  - tip
-matrix:
-  allow_failures:
-    - go: tip
-
-notifications:
-  email:
-    recipients: dean.karn@gmail.com
-    on_success: change
-    on_failure: always
-
-before_install:
-  - go install github.com/mattn/goveralls
-  - mkdir -p $GOPATH/src/gopkg.in
-  - ln -s $GOPATH/src/github.com/$TRAVIS_REPO_SLUG $GOPATH/src/gopkg.in/validator.v9
-
-# Only clone the most recent commit.
-git:
-  depth: 1
-
-script:
-  - go test -v -race -covermode=atomic -coverprofile=coverage.coverprofile ./...
-
-after_success: |
-  [ $TRAVIS_GO_VERSION = 1.15.2 ] &&
-  goveralls -coverprofile=coverage.coverprofile -service travis-ci -repotoken $COVERALLS_TOKEN
diff --git a/README.md b/README.md
index 054f294..04fbb3c 100644
--- a/README.md
+++ b/README.md
@@ -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)
diff --git a/baked_in.go b/baked_in.go
index ca3d3b9..91fa2c7 100644
--- a/baked_in.go
+++ b/baked_in.go
@@ -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,
 	}
@@ -1544,7 +1544,7 @@ func requiredWithout(fl FieldLevel) bool {
 	return true
 }
 
-// RequiredWithoutAll is the validation function
+// ExcludedWithoutAll is the validation function
 // The field under validation must not be present or is empty when all of the other specified fields are not present.
 func excludedWithoutAll(fl FieldLevel) bool {
 	params := parseOneOfParam2(fl.Param())
@@ -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()))
diff --git a/util.go b/util.go
index 6e568f8..56420f4 100644
--- a/util.go
+++ b/util.go
@@ -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)
 }
 
diff --git a/validator_instance.go b/validator_instance.go
index fe6a487..6fbd53a 100644
--- a/validator_instance.go
+++ b/validator_instance.go
@@ -29,6 +29,10 @@ const (
 	requiredWithAllTag    = "required_with_all"
 	requiredIfTag         = "required_if"
 	requiredUnlessTag     = "required_unless"
+	excludedWithoutAllTag = "excluded_without_all"
+	excludedWithoutTag    = "excluded_without"
+	excludedWithTag       = "excluded_with"
+	excludedWithAllTag    = "excluded_with_all"
 	skipValidationTag     = "-"
 	diveTag               = "dive"
 	keysTag               = "keys"
@@ -111,7 +115,8 @@ func New() *Validate {
 
 		switch k {
 		// these require that even if the value is nil that the validation should run, omitempty still overrides this behaviour
-		case requiredIfTag, requiredUnlessTag, requiredWithTag, requiredWithAllTag, requiredWithoutTag, requiredWithoutAllTag:
+		case requiredIfTag, requiredUnlessTag, requiredWithTag, requiredWithAllTag, requiredWithoutTag, requiredWithoutAllTag,
+			excludedWithTag, excludedWithAllTag, excludedWithoutTag, excludedWithoutAllTag:
 			_ = v.registerValidation(k, wrapFunc(val), true, true)
 		default:
 			// no need to error check here, baked in will always be valid


Test patch:
diff --git a/validator_test.go b/validator_test.go
index a918bce..76062a0 100644
--- a/validator_test.go
+++ b/validator_test.go
@@ -1789,7 +1789,7 @@ func TestCrossStructEqFieldValidation(t *testing.T) {
 	errs = validate.Struct(test)
 	Equal(t, errs, nil)
 
-	newTime := time.Now().UTC()
+	newTime := time.Now().Add(time.Hour).UTC()
 	test.CreatedAt = &newTime
 
 	errs = validate.Struct(test)
@@ -4607,7 +4607,7 @@ func TestIsNeFieldValidation(t *testing.T) {
 	NotEqual(t, errs, nil)
 	AssertError(t, errs, "Test.Start", "Test.Start", "Start", "Start", "nefield")
 
-	now3 := time.Now().UTC()
+	now3 := time.Now().Add(time.Hour).UTC()
 
 	sv = &Test{
 		Start: &now,
@@ -4840,7 +4840,7 @@ func TestIsEqFieldValidation(t *testing.T) {
 	errs = validate.Struct(sv)
 	Equal(t, errs, nil)
 
-	now3 := time.Now().UTC()
+	now3 := time.Now().Add(time.Hour).UTC()
 
 	sv = &Test{
 		Start: &now,
@@ -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) {
@@ -10202,6 +10202,28 @@ func TestExcludedWith(t *testing.T) {
 		name := fmt.Sprintf("Field%d", i)
 		AssertError(t, errs, name, name, name, name, "excluded_with")
 	}
+
+	test3 := struct {
+		Inner  *Inner
+		Inner2 *Inner
+		Field  string            `validate:"omitempty" json:"field"`
+		FieldE string            `validate:"omitempty" json:"field_e"`
+		Field1 string            `validate:"excluded_with=FieldE" json:"field_1"`
+		Field2 *string           `validate:"excluded_with=FieldE" json:"field_2"`
+		Field3 map[string]string `validate:"excluded_with=FieldE" json:"field_3"`
+		Field4 interface{}       `validate:"excluded_with=FieldE" json:"field_4"`
+		Field5 string            `validate:"excluded_with=Inner.FieldE" json:"field_5"`
+		Field6 string            `validate:"excluded_with=Inner2.FieldE" json:"field_6"`
+	}{
+		Inner:  &Inner{FieldE: "populated"},
+		Inner2: &Inner{FieldE: "populated"},
+		FieldE: "populated",
+	}
+
+	validate = New()
+
+	errs = validate.Struct(test3)
+	Equal(t, errs, nil)
 }
 
 func TestExcludedWithout(t *testing.T) {
@@ -10266,6 +10288,26 @@ func TestExcludedWithout(t *testing.T) {
 		name := fmt.Sprintf("Field%d", i)
 		AssertError(t, errs, name, name, name, name, "excluded_without")
 	}
+
+	test3 := struct {
+		Inner  *Inner
+		Inner2 *Inner
+		Field  string            `validate:"omitempty" json:"field"`
+		FieldE string            `validate:"omitempty" json:"field_e"`
+		Field1 string            `validate:"excluded_without=Field" json:"field_1"`
+		Field2 *string           `validate:"excluded_without=Field" json:"field_2"`
+		Field3 map[string]string `validate:"excluded_without=Field" json:"field_3"`
+		Field4 interface{}       `validate:"excluded_without=Field" json:"field_4"`
+		Field5 string            `validate:"excluded_without=Inner.Field" json:"field_5"`
+	}{
+		Inner: &Inner{Field: &fieldVal},
+		Field: "populated",
+	}
+
+	validate = New()
+
+	errs = validate.Struct(test3)
+	Equal(t, errs, nil)
 }
 
 func TestExcludedWithAll(t *testing.T) {
@@ -10334,6 +10376,29 @@ func TestExcludedWithAll(t *testing.T) {
 		name := fmt.Sprintf("Field%d", i)
 		AssertError(t, errs, name, name, name, name, "excluded_with_all")
 	}
+
+	test3 := struct {
+		Inner  *Inner
+		Inner2 *Inner
+		Field  string            `validate:"omitempty" json:"field"`
+		FieldE string            `validate:"omitempty" json:"field_e"`
+		Field1 string            `validate:"excluded_with_all=FieldE Field" json:"field_1"`
+		Field2 *string           `validate:"excluded_with_all=FieldE Field" json:"field_2"`
+		Field3 map[string]string `validate:"excluded_with_all=FieldE Field" json:"field_3"`
+		Field4 interface{}       `validate:"excluded_with_all=FieldE Field" json:"field_4"`
+		Field5 string            `validate:"excluded_with_all=Inner.FieldE" json:"field_5"`
+		Field6 string            `validate:"excluded_with_all=Inner2.FieldE" json:"field_6"`
+	}{
+		Inner:  &Inner{FieldE: "populated"},
+		Inner2: &Inner{FieldE: "populated"},
+		Field:  "populated",
+		FieldE: "populated",
+	}
+
+	validate = New()
+
+	errs = validate.Struct(test3)
+	Equal(t, errs, nil)
 }
 
 func TestExcludedWithoutAll(t *testing.T) {
@@ -10352,9 +10417,10 @@ func TestExcludedWithoutAll(t *testing.T) {
 		Field2 *string           `validate:"excluded_without_all=Field FieldE" json:"field_2"`
 		Field3 map[string]string `validate:"excluded_without_all=Field FieldE" json:"field_3"`
 		Field4 interface{}       `validate:"excluded_without_all=Field FieldE" json:"field_4"`
-		Field5 string            `validate:"excluded_without_all=Inner.Field Inner.Field2" json:"field_5"`
+		Field5 string            `validate:"excluded_without_all=Inner.Field Inner2.Field" json:"field_5"`
 	}{
 		Inner:  &Inner{Field: &fieldVal},
+		Inner2: &Inner{Field: &fieldVal},
 		Field:  "populated",
 		Field1: fieldVal,
 		Field2: &fieldVal,
@@ -10398,6 +10464,28 @@ func TestExcludedWithoutAll(t *testing.T) {
 		name := fmt.Sprintf("Field%d", i)
 		AssertError(t, errs, name, name, name, name, "excluded_without_all")
 	}
+
+	test3 := struct {
+		Inner  *Inner
+		Inner2 *Inner
+		Field  string            `validate:"omitempty" json:"field"`
+		FieldE string            `validate:"omitempty" json:"field_e"`
+		Field1 string            `validate:"excluded_without_all=Field FieldE" json:"field_1"`
+		Field2 *string           `validate:"excluded_without_all=Field FieldE" json:"field_2"`
+		Field3 map[string]string `validate:"excluded_without_all=Field FieldE" json:"field_3"`
+		Field4 interface{}       `validate:"excluded_without_all=Field FieldE" json:"field_4"`
+		Field5 string            `validate:"excluded_without_all=Inner.Field Inner2.Field" json:"field_5"`
+	}{
+		Inner:  &Inner{Field: &fieldVal},
+		Inner2: &Inner{Field: &fieldVal},
+		Field:  "populated",
+		FieldE: "populated",
+	}
+
+	validate = New()
+
+	errs = validate.Struct(test3)
+	Equal(t, errs, nil)
 }
 
 func TestRequiredWithAll(t *testing.T) {
@@ -10989,4 +11077,47 @@ func TestTimeZoneValidation(t *testing.T) {
 	PanicMatches(t, func() {
 		_ = validate.Var(2, "timezone")
 	}, "Bad field type int")
-}
\ No newline at end of file
+}
+
+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)
+		})
+	}
+}