fix required_with_*

pull/523/head
Dean Karn 5 years ago
parent cc25246f01
commit 6484d9f2fb
  1. 26
      baked_in.go
  2. 68
      validator_test.go

@ -1314,19 +1314,19 @@ func hasValue(fl FieldLevel) bool {
} }
// requireCheckField is a func for check field kind // requireCheckField is a func for check field kind
func requireCheckFieldKind(fl FieldLevel, param string) bool { func requireCheckFieldKind(fl FieldLevel, param string, defaultNotFoundValue bool) bool {
field := fl.Field() field := fl.Field()
var ok bool var ok bool
kind := field.Kind() kind := field.Kind()
if len(param) > 0 { if len(param) > 0 {
field, kind, ok = fl.GetStructFieldOKAdvanced(fl.Parent(), param) field, kind, ok = fl.GetStructFieldOKAdvanced(fl.Parent(), param)
if !ok { if !ok {
return true return defaultNotFoundValue
} }
} }
switch kind { switch kind {
case reflect.Invalid: case reflect.Invalid:
return true return defaultNotFoundValue
case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func: case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func:
return !field.IsNil() return !field.IsNil()
default: default:
@ -1339,8 +1339,8 @@ func requireCheckFieldKind(fl FieldLevel, param string) bool {
func requiredWith(fl FieldLevel) bool { func requiredWith(fl FieldLevel) bool {
params := parseOneOfParam2(fl.Param()) params := parseOneOfParam2(fl.Param())
for _, param := range params { for _, param := range params {
if requireCheckFieldKind(fl, param) { if requireCheckFieldKind(fl, param, false) {
return requireCheckFieldKind(fl, "") return hasValue(fl)
} }
} }
return true return true
@ -1349,19 +1349,13 @@ func requiredWith(fl FieldLevel) bool {
// RequiredWithAll is the validation function // RequiredWithAll is the validation function
// The field under validation must be present and not empty only if all of the other specified fields are present. // The field under validation must be present and not empty only if all of the other specified fields are present.
func requiredWithAll(fl FieldLevel) bool { func requiredWithAll(fl FieldLevel) bool {
isValidateCurrentField := true
params := parseOneOfParam2(fl.Param()) params := parseOneOfParam2(fl.Param())
for _, param := range params { for _, param := range params {
if !requireCheckFieldKind(fl, param, false) {
if !requireCheckFieldKind(fl, param) { return true
isValidateCurrentField = false
break
}
} }
if isValidateCurrentField {
return requireCheckFieldKind(fl, "")
} }
return true return hasValue(fl)
} }
// RequiredWithout is the validation function // RequiredWithout is the validation function
@ -1369,7 +1363,7 @@ func requiredWithAll(fl FieldLevel) bool {
func requiredWithout(fl FieldLevel) bool { func requiredWithout(fl FieldLevel) bool {
params := parseOneOfParam2(fl.Param()) params := parseOneOfParam2(fl.Param())
for _, param := range params { for _, param := range params {
if !requireCheckFieldKind(fl, param) { if !requireCheckFieldKind(fl, param, true) {
return hasValue(fl) return hasValue(fl)
} }
} }
@ -1381,7 +1375,7 @@ func requiredWithout(fl FieldLevel) bool {
func requiredWithoutAll(fl FieldLevel) bool { func requiredWithoutAll(fl FieldLevel) bool {
params := parseOneOfParam2(fl.Param()) params := parseOneOfParam2(fl.Param())
for _, param := range params { for _, param := range params {
if requireCheckFieldKind(fl, param) { if requireCheckFieldKind(fl, param, true) {
return true return true
} }
} }

@ -8621,17 +8621,22 @@ func TestEndsWithValidation(t *testing.T) {
} }
func TestRequiredWith(t *testing.T) { func TestRequiredWith(t *testing.T) {
type Inner struct {
Field *string
}
fieldVal := "test" fieldVal := "test"
test := struct { test := struct {
Inner *Inner
FieldE string `validate:"omitempty" json:"field_e"` FieldE string `validate:"omitempty" json:"field_e"`
FieldER string `validate:"required_with=FieldE" json:"field_er"` FieldER string `validate:"required_with=FieldE" json:"field_er"`
Field1 string `validate:"omitempty" json:"field_1"` Field1 string `validate:"omitempty" json:"field_1"`
Field2 *string `validate:"required_with=Field1" json:"field_2"` Field2 *string `validate:"required_with=Field1" json:"field_2"`
Field3 map[string]string `validate:"required_with=Field2" json:"field_3"` Field3 map[string]string `validate:"required_with=Field2" json:"field_3"`
Field4 interface{} `validate:"required_with=Field3" json:"field_4"` Field4 interface{} `validate:"required_with=Field3" json:"field_4"`
Field5 string `validate:"required_with=Field3" json:"field_5"` Field5 string `validate:"required_with=Inner.Field" json:"field_5"`
}{ }{
Field1: "test_field1", Inner: &Inner{Field: &fieldVal},
Field2: &fieldVal, Field2: &fieldVal,
Field3: map[string]string{"key": "val"}, Field3: map[string]string{"key": "val"},
Field4: "test", Field4: "test",
@ -8641,24 +8646,52 @@ func TestRequiredWith(t *testing.T) {
validate := New() validate := New()
errs := validate.Struct(test) errs := validate.Struct(test)
Equal(t, errs, nil)
if errs != nil { test2 := struct {
t.Fatalf("failed Error: %s", errs) Inner *Inner
Inner2 *Inner
FieldE string `validate:"omitempty" json:"field_e"`
FieldER string `validate:"required_with=FieldE" json:"field_er"`
Field1 string `validate:"omitempty" json:"field_1"`
Field2 *string `validate:"required_with=Field1" json:"field_2"`
Field3 map[string]string `validate:"required_with=Field2" json:"field_3"`
Field4 interface{} `validate:"required_with=Field2" json:"field_4"`
Field5 string `validate:"required_with=Field3" json:"field_5"`
Field6 string `validate:"required_with=Inner.Field" json:"field_6"`
Field7 string `validate:"required_with=Inner2.Field" json:"field_7"`
}{
Inner: &Inner{Field: &fieldVal},
Field2: &fieldVal,
} }
errs = validate.Struct(test2)
NotEqual(t, errs, nil)
ve := errs.(ValidationErrors)
Equal(t, len(ve), 3)
AssertError(t, errs, "Field3", "Field3", "Field3", "Field3", "required_with")
AssertError(t, errs, "Field4", "Field4", "Field4", "Field4", "required_with")
AssertError(t, errs, "Field6", "Field6", "Field6", "Field6", "required_with")
} }
func TestRequiredWithAll(t *testing.T) { func TestRequiredWithAll(t *testing.T) {
type Inner struct {
Field *string
}
fieldVal := "test" fieldVal := "test"
test := struct { test := struct {
Inner *Inner
FieldE string `validate:"omitempty" json:"field_e"` FieldE string `validate:"omitempty" json:"field_e"`
FieldER string `validate:"required_with_all=FieldE" json:"field_er"` FieldER string `validate:"required_with_all=FieldE" json:"field_er"`
Field1 string `validate:"omitempty" json:"field_1"` Field1 string `validate:"omitempty" json:"field_1"`
Field2 *string `validate:"required_with_all=Field1" json:"field_2"` Field2 *string `validate:"required_with_all=Field1" json:"field_2"`
Field3 map[string]string `validate:"required_with_all=Field2" json:"field_3"` Field3 map[string]string `validate:"required_with_all=Field2" json:"field_3"`
Field4 interface{} `validate:"required_with_all=Field3" json:"field_4"` Field4 interface{} `validate:"required_with_all=Field3" json:"field_4"`
Field5 string `validate:"required_with_all=Field3" json:"field_5"` Field5 string `validate:"required_with_all=Inner.Field" json:"field_5"`
}{ }{
Inner: &Inner{Field: &fieldVal},
Field1: "test_field1", Field1: "test_field1",
Field2: &fieldVal, Field2: &fieldVal,
Field3: map[string]string{"key": "val"}, Field3: map[string]string{"key": "val"},
@ -8669,10 +8702,31 @@ func TestRequiredWithAll(t *testing.T) {
validate := New() validate := New()
errs := validate.Struct(test) errs := validate.Struct(test)
Equal(t, errs, nil)
if errs != nil { test2 := struct {
t.Fatalf("failed Error: %s", errs) Inner *Inner
Inner2 *Inner
FieldE string `validate:"omitempty" json:"field_e"`
FieldER string `validate:"required_with_all=FieldE" json:"field_er"`
Field1 string `validate:"omitempty" json:"field_1"`
Field2 *string `validate:"required_with_all=Field1" json:"field_2"`
Field3 map[string]string `validate:"required_with_all=Field2" json:"field_3"`
Field4 interface{} `validate:"required_with_all=Field1 FieldE" json:"field_4"`
Field5 string `validate:"required_with_all=Inner.Field Field2" json:"field_5"`
Field6 string `validate:"required_with_all=Inner2.Field Field2" json:"field_6"`
}{
Inner: &Inner{Field: &fieldVal},
Field2: &fieldVal,
} }
errs = validate.Struct(test2)
NotEqual(t, errs, nil)
ve := errs.(ValidationErrors)
Equal(t, len(ve), 2)
AssertError(t, errs, "Field3", "Field3", "Field3", "Field3", "required_with_all")
AssertError(t, errs, "Field5", "Field5", "Field5", "Field5", "required_with_all")
} }
func TestRequiredWithout(t *testing.T) { func TestRequiredWithout(t *testing.T) {

Loading…
Cancel
Save