Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions baked_in.go
Original file line number Diff line number Diff line change
Expand Up @@ -1872,6 +1872,15 @@ func requiredIf(fl FieldLevel) bool {
if len(params)%2 != 0 {
panic(fmt.Sprintf("Bad param number for required_if %s", fl.FieldName()))
}

seen := make(map[string]struct{})
for i := 0; i < len(params); i += 2 {
if _, ok := seen[params[i]]; ok {
panic(fmt.Sprintf("Duplicate param %s for required_if %s", params[i], fl.FieldName()))
}
seen[params[i]] = struct{}{}
}

for i := 0; i < len(params); i += 2 {
if !requireCheckFieldValue(fl, params[i], params[i+1], false) {
return true
Expand Down
5 changes: 5 additions & 0 deletions doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,8 @@ interfaces, channels and functions ensures the value is not nil. For structs ens

Usage: required_if

NOTE: Duplicate field names in the parameters will cause a panic error.

Examples:

// require the field if the Field1 is equal to the parameter given:
Expand All @@ -275,6 +277,9 @@ Examples:
// require the field if the Field1 and Field2 is equal to the value respectively:
Usage: required_if=Field1 foo Field2 bar

// INVALID: duplicate field names will cause a panic error:
Usage: required_if=Field1 foo Field1 bar

# Required Unless

The field under validation must be present and not empty unless all
Expand Down
84 changes: 74 additions & 10 deletions validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11099,6 +11099,49 @@ func TestRequiredIf(t *testing.T) {
_ = validate.Struct(test3)
}

func TestRequiredIfDuplicateParams(t *testing.T) {
validate := New()

PanicMatches(t, func() {
type TestStruct struct {
Field1 string `validate:"required_if=Field2 value1 Field2 value2"`
Field2 string
}
test := TestStruct{
Field1: "",
Field2: "value1",
}
_ = validate.Struct(test)
}, "Duplicate param Field2 for required_if Field1")

PanicMatches(t, func() {
type TestStruct struct {
Field1 string `validate:"required_if=Field2 val1 Field3 val2 Field2 val3"`
Field2 string
Field3 string
}
test := TestStruct{
Field1: "",
Field2: "val1",
Field3: "val2",
}
_ = validate.Struct(test)
}, "Duplicate param Field2 for required_if Field1")

type TestStruct struct {
Field1 string `validate:"required_if=Field2 val1 Field3 val2"`
Field2 string
Field3 string
}
test := TestStruct{
Field1: "",
Field2: "val1",
Field3: "val2",
}
errs := validate.Struct(test)
NotEqual(t, errs, nil)
}

func TestRequiredUnless(t *testing.T) {
type Inner struct {
Field *string
Expand Down Expand Up @@ -11169,19 +11212,40 @@ func TestRequiredUnless(t *testing.T) {
AssertError(t, errs, "Field10", "Field10", "Field10", "Field10", "required_unless")
AssertError(t, errs, "Field11", "Field11", "Field11", "Field11", "required_unless")

defer func() {
if r := recover(); r == nil {
t.Errorf("test3 should have panicked!")
PanicMatches(t, func() {
test3 := struct {
Inner *Inner
Field1 string `validate:"required_unless=Inner.Field" json:"field_1"`
}{
Inner: &Inner{Field: &fieldVal},
}
}()
_ = validate.Struct(test3)
}, "Bad param number for required_unless Field1")

test3 := struct {
Inner *Inner
Field1 string `validate:"required_unless=Inner.Field" json:"field_1"`
}{
Inner: &Inner{Field: &fieldVal},
type DuplicateStruct struct {
Field1 string `validate:"required_unless=Field2 value1 Field2 value2"`
Field2 string
}
_ = validate.Struct(test3)
test4 := DuplicateStruct{
Field1: "",
Field2: "value1",
}
errs = validate.Struct(test4)
Equal(t, errs, nil)

test5 := DuplicateStruct{
Field1: "",
Field2: "value2",
}
errs = validate.Struct(test5)
Equal(t, errs, nil)

test6 := DuplicateStruct{
Field1: "",
Field2: "value3",
}
errs = validate.Struct(test6)
NotEqual(t, errs, nil)
}

func TestSkipUnless(t *testing.T) {
Expand Down
Loading