Skip to content

Commit 6484d9f

Browse files
author
Dean Karn
committed
fix required_with_*
1 parent cc25246 commit 6484d9f

File tree

2 files changed

+71
-23
lines changed

2 files changed

+71
-23
lines changed

baked_in.go

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1314,19 +1314,19 @@ func hasValue(fl FieldLevel) bool {
13141314
}
13151315

13161316
// requireCheckField is a func for check field kind
1317-
func requireCheckFieldKind(fl FieldLevel, param string) bool {
1317+
func requireCheckFieldKind(fl FieldLevel, param string, defaultNotFoundValue bool) bool {
13181318
field := fl.Field()
13191319
var ok bool
13201320
kind := field.Kind()
13211321
if len(param) > 0 {
13221322
field, kind, ok = fl.GetStructFieldOKAdvanced(fl.Parent(), param)
13231323
if !ok {
1324-
return true
1324+
return defaultNotFoundValue
13251325
}
13261326
}
13271327
switch kind {
13281328
case reflect.Invalid:
1329-
return true
1329+
return defaultNotFoundValue
13301330
case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func:
13311331
return !field.IsNil()
13321332
default:
@@ -1339,8 +1339,8 @@ func requireCheckFieldKind(fl FieldLevel, param string) bool {
13391339
func requiredWith(fl FieldLevel) bool {
13401340
params := parseOneOfParam2(fl.Param())
13411341
for _, param := range params {
1342-
if requireCheckFieldKind(fl, param) {
1343-
return requireCheckFieldKind(fl, "")
1342+
if requireCheckFieldKind(fl, param, false) {
1343+
return hasValue(fl)
13441344
}
13451345
}
13461346
return true
@@ -1349,27 +1349,21 @@ func requiredWith(fl FieldLevel) bool {
13491349
// RequiredWithAll is the validation function
13501350
// The field under validation must be present and not empty only if all of the other specified fields are present.
13511351
func requiredWithAll(fl FieldLevel) bool {
1352-
isValidateCurrentField := true
13531352
params := parseOneOfParam2(fl.Param())
13541353
for _, param := range params {
1355-
1356-
if !requireCheckFieldKind(fl, param) {
1357-
isValidateCurrentField = false
1358-
break
1354+
if !requireCheckFieldKind(fl, param, false) {
1355+
return true
13591356
}
13601357
}
1361-
if isValidateCurrentField {
1362-
return requireCheckFieldKind(fl, "")
1363-
}
1364-
return true
1358+
return hasValue(fl)
13651359
}
13661360

13671361
// RequiredWithout is the validation function
13681362
// The field under validation must be present and not empty only when any of the other specified fields are not present.
13691363
func requiredWithout(fl FieldLevel) bool {
13701364
params := parseOneOfParam2(fl.Param())
13711365
for _, param := range params {
1372-
if !requireCheckFieldKind(fl, param) {
1366+
if !requireCheckFieldKind(fl, param, true) {
13731367
return hasValue(fl)
13741368
}
13751369
}
@@ -1381,7 +1375,7 @@ func requiredWithout(fl FieldLevel) bool {
13811375
func requiredWithoutAll(fl FieldLevel) bool {
13821376
params := parseOneOfParam2(fl.Param())
13831377
for _, param := range params {
1384-
if requireCheckFieldKind(fl, param) {
1378+
if requireCheckFieldKind(fl, param, true) {
13851379
return true
13861380
}
13871381
}

validator_test.go

Lines changed: 61 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8621,17 +8621,22 @@ func TestEndsWithValidation(t *testing.T) {
86218621
}
86228622

86238623
func TestRequiredWith(t *testing.T) {
8624+
type Inner struct {
8625+
Field *string
8626+
}
8627+
86248628
fieldVal := "test"
86258629
test := struct {
8630+
Inner *Inner
86268631
FieldE string `validate:"omitempty" json:"field_e"`
86278632
FieldER string `validate:"required_with=FieldE" json:"field_er"`
86288633
Field1 string `validate:"omitempty" json:"field_1"`
86298634
Field2 *string `validate:"required_with=Field1" json:"field_2"`
86308635
Field3 map[string]string `validate:"required_with=Field2" json:"field_3"`
86318636
Field4 interface{} `validate:"required_with=Field3" json:"field_4"`
8632-
Field5 string `validate:"required_with=Field3" json:"field_5"`
8637+
Field5 string `validate:"required_with=Inner.Field" json:"field_5"`
86338638
}{
8634-
Field1: "test_field1",
8639+
Inner: &Inner{Field: &fieldVal},
86358640
Field2: &fieldVal,
86368641
Field3: map[string]string{"key": "val"},
86378642
Field4: "test",
@@ -8641,24 +8646,52 @@ func TestRequiredWith(t *testing.T) {
86418646
validate := New()
86428647

86438648
errs := validate.Struct(test)
8649+
Equal(t, errs, nil)
86448650

8645-
if errs != nil {
8646-
t.Fatalf("failed Error: %s", errs)
8651+
test2 := struct {
8652+
Inner *Inner
8653+
Inner2 *Inner
8654+
FieldE string `validate:"omitempty" json:"field_e"`
8655+
FieldER string `validate:"required_with=FieldE" json:"field_er"`
8656+
Field1 string `validate:"omitempty" json:"field_1"`
8657+
Field2 *string `validate:"required_with=Field1" json:"field_2"`
8658+
Field3 map[string]string `validate:"required_with=Field2" json:"field_3"`
8659+
Field4 interface{} `validate:"required_with=Field2" json:"field_4"`
8660+
Field5 string `validate:"required_with=Field3" json:"field_5"`
8661+
Field6 string `validate:"required_with=Inner.Field" json:"field_6"`
8662+
Field7 string `validate:"required_with=Inner2.Field" json:"field_7"`
8663+
}{
8664+
Inner: &Inner{Field: &fieldVal},
8665+
Field2: &fieldVal,
86478666
}
8667+
8668+
errs = validate.Struct(test2)
8669+
NotEqual(t, errs, nil)
8670+
8671+
ve := errs.(ValidationErrors)
8672+
Equal(t, len(ve), 3)
8673+
AssertError(t, errs, "Field3", "Field3", "Field3", "Field3", "required_with")
8674+
AssertError(t, errs, "Field4", "Field4", "Field4", "Field4", "required_with")
8675+
AssertError(t, errs, "Field6", "Field6", "Field6", "Field6", "required_with")
86488676
}
86498677

86508678
func TestRequiredWithAll(t *testing.T) {
8679+
type Inner struct {
8680+
Field *string
8681+
}
86518682

86528683
fieldVal := "test"
86538684
test := struct {
8685+
Inner *Inner
86548686
FieldE string `validate:"omitempty" json:"field_e"`
86558687
FieldER string `validate:"required_with_all=FieldE" json:"field_er"`
86568688
Field1 string `validate:"omitempty" json:"field_1"`
86578689
Field2 *string `validate:"required_with_all=Field1" json:"field_2"`
86588690
Field3 map[string]string `validate:"required_with_all=Field2" json:"field_3"`
86598691
Field4 interface{} `validate:"required_with_all=Field3" json:"field_4"`
8660-
Field5 string `validate:"required_with_all=Field3" json:"field_5"`
8692+
Field5 string `validate:"required_with_all=Inner.Field" json:"field_5"`
86618693
}{
8694+
Inner: &Inner{Field: &fieldVal},
86628695
Field1: "test_field1",
86638696
Field2: &fieldVal,
86648697
Field3: map[string]string{"key": "val"},
@@ -8669,10 +8702,31 @@ func TestRequiredWithAll(t *testing.T) {
86698702
validate := New()
86708703

86718704
errs := validate.Struct(test)
8705+
Equal(t, errs, nil)
86728706

8673-
if errs != nil {
8674-
t.Fatalf("failed Error: %s", errs)
8707+
test2 := struct {
8708+
Inner *Inner
8709+
Inner2 *Inner
8710+
FieldE string `validate:"omitempty" json:"field_e"`
8711+
FieldER string `validate:"required_with_all=FieldE" json:"field_er"`
8712+
Field1 string `validate:"omitempty" json:"field_1"`
8713+
Field2 *string `validate:"required_with_all=Field1" json:"field_2"`
8714+
Field3 map[string]string `validate:"required_with_all=Field2" json:"field_3"`
8715+
Field4 interface{} `validate:"required_with_all=Field1 FieldE" json:"field_4"`
8716+
Field5 string `validate:"required_with_all=Inner.Field Field2" json:"field_5"`
8717+
Field6 string `validate:"required_with_all=Inner2.Field Field2" json:"field_6"`
8718+
}{
8719+
Inner: &Inner{Field: &fieldVal},
8720+
Field2: &fieldVal,
86758721
}
8722+
8723+
errs = validate.Struct(test2)
8724+
NotEqual(t, errs, nil)
8725+
8726+
ve := errs.(ValidationErrors)
8727+
Equal(t, len(ve), 2)
8728+
AssertError(t, errs, "Field3", "Field3", "Field3", "Field3", "required_with_all")
8729+
AssertError(t, errs, "Field5", "Field5", "Field5", "Field5", "required_with_all")
86768730
}
86778731

86788732
func TestRequiredWithout(t *testing.T) {

0 commit comments

Comments
 (0)