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 diff --git a/validator_test.go b/validator_test.go index 683a2dd..76062a0 100644 --- a/validator_test.go +++ b/validator_test.go @@ -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) {