mirror of
https://github.com/Fishwaldo/validator.git
synced 2025-03-15 11:41:32 +00:00
added excluded_if/excluded_unless tags + tests (#847)
This commit is contained in:
parent
58d5778b18
commit
c0195b2b40
5 changed files with 212 additions and 2 deletions
|
@ -219,6 +219,8 @@ Baked-in Validations
|
|||
| required_with_all | Required With All |
|
||||
| required_without | Required Without |
|
||||
| required_without_all | Required Without All |
|
||||
| excluded_if | Excluded If |
|
||||
| excluded_unless | Excluded Unless |
|
||||
| excluded_with | Excluded With |
|
||||
| excluded_with_all | Excluded With All |
|
||||
| excluded_without | Excluded Without |
|
||||
|
|
33
baked_in.go
33
baked_in.go
|
@ -75,6 +75,8 @@ var (
|
|||
"required_with_all": requiredWithAll,
|
||||
"required_without": requiredWithout,
|
||||
"required_without_all": requiredWithoutAll,
|
||||
"excluded_if": excludedIf,
|
||||
"excluded_unless": excludedUnless,
|
||||
"excluded_with": excludedWith,
|
||||
"excluded_with_all": excludedWithAll,
|
||||
"excluded_without": excludedWithout,
|
||||
|
@ -1542,6 +1544,22 @@ func requiredIf(fl FieldLevel) bool {
|
|||
return hasValue(fl)
|
||||
}
|
||||
|
||||
// excludedIf is the validation function
|
||||
// The field under validation must not be present or is empty only if all the other specified fields are equal to the value following with the specified field.
|
||||
func excludedIf(fl FieldLevel) bool {
|
||||
params := parseOneOfParam2(fl.Param())
|
||||
if len(params)%2 != 0 {
|
||||
panic(fmt.Sprintf("Bad param number for excluded_if %s", fl.FieldName()))
|
||||
}
|
||||
|
||||
for i := 0; i < len(params); i += 2 {
|
||||
if !requireCheckFieldValue(fl, params[i], params[i+1], false) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// requiredUnless is the validation function
|
||||
// The field under validation must be present and not empty only unless all the other specified fields are equal to the value following with the specified field.
|
||||
func requiredUnless(fl FieldLevel) bool {
|
||||
|
@ -1558,6 +1576,21 @@ func requiredUnless(fl FieldLevel) bool {
|
|||
return hasValue(fl)
|
||||
}
|
||||
|
||||
// excludedUnless is the validation function
|
||||
// The field under validation must not be present or is empty unless all the other specified fields are equal to the value following with the specified field.
|
||||
func excludedUnless(fl FieldLevel) bool {
|
||||
params := parseOneOfParam2(fl.Param())
|
||||
if len(params)%2 != 0 {
|
||||
panic(fmt.Sprintf("Bad param number for excluded_unless %s", fl.FieldName()))
|
||||
}
|
||||
for i := 0; i < len(params); i += 2 {
|
||||
if !requireCheckFieldValue(fl, params[i], params[i+1], false) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return !hasValue(fl)
|
||||
}
|
||||
|
||||
// excludedWith is the validation function
|
||||
// The field under validation must not be present or is empty if any of the other specified fields are present.
|
||||
func excludedWith(fl FieldLevel) bool {
|
||||
|
|
34
doc.go
34
doc.go
|
@ -349,6 +349,40 @@ Example:
|
|||
// require the field if the Field1 and Field2 is not present:
|
||||
Usage: required_without_all=Field1 Field2
|
||||
|
||||
Excluded If
|
||||
|
||||
The field under validation must not be present or not empty only if all
|
||||
the other specified fields are equal to the value following the specified
|
||||
field. For strings ensures value is not "". For slices, maps, pointers,
|
||||
interfaces, channels and functions ensures the value is not nil.
|
||||
|
||||
Usage: excluded_if
|
||||
|
||||
Examples:
|
||||
|
||||
// exclude the field if the Field1 is equal to the parameter given:
|
||||
Usage: excluded_if=Field1 foobar
|
||||
|
||||
// exclude the field if the Field1 and Field2 is equal to the value respectively:
|
||||
Usage: excluded_if=Field1 foo Field2 bar
|
||||
|
||||
Excluded Unless
|
||||
|
||||
The field under validation must not be present or empty unless all
|
||||
the other specified fields are equal to the value following the specified
|
||||
field. For strings ensures value is not "". For slices, maps, pointers,
|
||||
interfaces, channels and functions ensures the value is not nil.
|
||||
|
||||
Usage: excluded_unless
|
||||
|
||||
Examples:
|
||||
|
||||
// exclude the field unless the Field1 is equal to the parameter given:
|
||||
Usage: excluded_unless=Field1 foobar
|
||||
|
||||
// exclude the field unless the Field1 and Field2 is equal to the value respectively:
|
||||
Usage: excluded_unless=Field1 foo Field2 bar
|
||||
|
||||
Is Default
|
||||
|
||||
This validates that the value is the default value and is almost the
|
||||
|
|
|
@ -33,6 +33,8 @@ const (
|
|||
excludedWithoutTag = "excluded_without"
|
||||
excludedWithTag = "excluded_with"
|
||||
excludedWithAllTag = "excluded_with_all"
|
||||
excludedIfTag = "excluded_if"
|
||||
excludedUnlessTag = "excluded_unless"
|
||||
skipValidationTag = "-"
|
||||
diveTag = "dive"
|
||||
keysTag = "keys"
|
||||
|
@ -120,7 +122,7 @@ 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,
|
||||
excludedWithTag, excludedWithAllTag, excludedWithoutTag, excludedWithoutAllTag:
|
||||
excludedIfTag, excludedUnlessTag, excludedWithTag, excludedWithAllTag, excludedWithoutTag, excludedWithoutAllTag:
|
||||
_ = v.registerValidation(k, wrapFunc(val), true, true)
|
||||
default:
|
||||
// no need to error check here, baked in will always be valid
|
||||
|
|
|
@ -10675,6 +10675,145 @@ func TestRequiredWithoutAll(t *testing.T) {
|
|||
AssertError(t, errs, "Field2", "Field2", "Field2", "Field2", "required_without_all")
|
||||
}
|
||||
|
||||
func TestExcludedIf(t *testing.T) {
|
||||
validate := New()
|
||||
type Inner struct {
|
||||
Field *string
|
||||
}
|
||||
|
||||
test1 := struct {
|
||||
FieldE string `validate:"omitempty" json:"field_e"`
|
||||
FieldER *string `validate:"excluded_if=FieldE test" json:"field_er"`
|
||||
}{
|
||||
FieldE: "test",
|
||||
}
|
||||
errs := validate.Struct(test1)
|
||||
Equal(t, errs, nil)
|
||||
|
||||
test2 := struct {
|
||||
FieldE string `validate:"omitempty" json:"field_e"`
|
||||
FieldER string `validate:"excluded_if=FieldE test" json:"field_er"`
|
||||
}{
|
||||
FieldE: "notest",
|
||||
}
|
||||
errs = validate.Struct(test2)
|
||||
NotEqual(t, errs, nil)
|
||||
ve := errs.(ValidationErrors)
|
||||
Equal(t, len(ve), 1)
|
||||
AssertError(t, errs, "FieldER", "FieldER", "FieldER", "FieldER", "excluded_if")
|
||||
|
||||
shouldError := "shouldError"
|
||||
test3 := struct {
|
||||
Inner *Inner
|
||||
FieldE string `validate:"omitempty" json:"field_e"`
|
||||
Field1 int `validate:"excluded_if=Inner.Field test" json:"field_1"`
|
||||
}{
|
||||
Inner: &Inner{Field: &shouldError},
|
||||
}
|
||||
errs = validate.Struct(test3)
|
||||
NotEqual(t, errs, nil)
|
||||
ve = errs.(ValidationErrors)
|
||||
Equal(t, len(ve), 1)
|
||||
AssertError(t, errs, "Field1", "Field1", "Field1", "Field1", "excluded_if")
|
||||
|
||||
shouldPass := "test"
|
||||
test4 := struct {
|
||||
Inner *Inner
|
||||
FieldE string `validate:"omitempty" json:"field_e"`
|
||||
Field1 int `validate:"excluded_if=Inner.Field test" json:"field_1"`
|
||||
}{
|
||||
Inner: &Inner{Field: &shouldPass},
|
||||
}
|
||||
errs = validate.Struct(test4)
|
||||
Equal(t, errs, nil)
|
||||
|
||||
// Checks number of params in struct tag is correct
|
||||
defer func() {
|
||||
if r := recover(); r == nil {
|
||||
t.Errorf("panicTest should have panicked!")
|
||||
}
|
||||
}()
|
||||
fieldVal := "panicTest"
|
||||
panicTest := struct {
|
||||
Inner *Inner
|
||||
Field1 string `validate:"excluded_if=Inner.Field" json:"field_1"`
|
||||
}{
|
||||
Inner: &Inner{Field: &fieldVal},
|
||||
}
|
||||
_ = validate.Struct(panicTest)
|
||||
}
|
||||
|
||||
func TestExcludedUnless(t *testing.T) {
|
||||
validate := New()
|
||||
type Inner struct {
|
||||
Field *string
|
||||
}
|
||||
|
||||
fieldVal := "test"
|
||||
test := struct {
|
||||
FieldE string `validate:"omitempty" json:"field_e"`
|
||||
FieldER string `validate:"excluded_unless=FieldE test" json:"field_er"`
|
||||
}{
|
||||
FieldE: "notest",
|
||||
FieldER: "filled",
|
||||
}
|
||||
errs := validate.Struct(test)
|
||||
Equal(t, errs, nil)
|
||||
|
||||
test2 := struct {
|
||||
FieldE string `validate:"omitempty" json:"field_e"`
|
||||
FieldER string `validate:"excluded_unless=FieldE test" json:"field_er"`
|
||||
}{
|
||||
FieldE: "test",
|
||||
FieldER: "filled",
|
||||
}
|
||||
errs = validate.Struct(test2)
|
||||
NotEqual(t, errs, nil)
|
||||
ve := errs.(ValidationErrors)
|
||||
Equal(t, len(ve), 1)
|
||||
AssertError(t, errs, "FieldER", "FieldER", "FieldER", "FieldER", "excluded_unless")
|
||||
|
||||
shouldError := "test"
|
||||
test3 := struct {
|
||||
Inner *Inner
|
||||
Field1 string `validate:"excluded_unless=Inner.Field test" json:"field_1"`
|
||||
}{
|
||||
Inner: &Inner{Field: &shouldError},
|
||||
Field1: "filled",
|
||||
}
|
||||
errs = validate.Struct(test3)
|
||||
NotEqual(t, errs, nil)
|
||||
ve = errs.(ValidationErrors)
|
||||
Equal(t, len(ve), 1)
|
||||
AssertError(t, errs, "Field1", "Field1", "Field1", "Field1", "excluded_unless")
|
||||
|
||||
shouldPass := "shouldPass"
|
||||
test4 := struct {
|
||||
Inner *Inner
|
||||
FieldE string `validate:"omitempty" json:"field_e"`
|
||||
Field1 string `validate:"excluded_unless=Inner.Field test" json:"field_1"`
|
||||
}{
|
||||
Inner: &Inner{Field: &shouldPass},
|
||||
Field1: "filled",
|
||||
}
|
||||
errs = validate.Struct(test4)
|
||||
Equal(t, errs, nil)
|
||||
|
||||
// Checks number of params in struct tag is correct
|
||||
defer func() {
|
||||
if r := recover(); r == nil {
|
||||
t.Errorf("panicTest should have panicked!")
|
||||
}
|
||||
}()
|
||||
panicTest := struct {
|
||||
Inner *Inner
|
||||
Field1 string `validate:"excluded_unless=Inner.Field" json:"field_1"`
|
||||
}{
|
||||
Inner: &Inner{Field: &fieldVal},
|
||||
}
|
||||
_ = validate.Struct(panicTest)
|
||||
}
|
||||
|
||||
func TestLookup(t *testing.T) {
|
||||
type Lookup struct {
|
||||
FieldA *string `json:"fieldA,omitempty" validate:"required_without=FieldB"`
|
||||
|
@ -11460,7 +11599,7 @@ func TestSemverFormatValidation(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func TestRFC1035LabelFormatValidation(t *testing.T) {
|
||||
tests := []struct {
|
||||
value string `validate:"dns_rfc1035_label"`
|
||||
|
|
Loading…
Add table
Reference in a new issue