diff --git a/validator.go b/validator.go index 5c918fc..72ffff5 100644 --- a/validator.go +++ b/validator.go @@ -923,7 +923,7 @@ func ValidateMap(s map[string]interface{}, m map[string]interface{}) (bool, erro Offset: 0, Index: []int{index}, Anonymous: false, - }, val, nil) + }, val, nil, val) if err != nil { errs = append(errs, err) } @@ -1001,7 +1001,7 @@ func ValidateStruct(s interface{}) (bool, error) { errs = append(errs, err) } } - resultField, err2 := typeCheck(valueField, typeField, val, nil) + resultField, err2 := typeCheck(valueField, typeField, val, nil, val) if err2 != nil { // Replace structure name with JSON name if there is a tag on the variable @@ -1297,7 +1297,7 @@ func checkRequired(v reflect.Value, t reflect.StructField, options tagOptionsMap return true, nil } -func typeCheck(v reflect.Value, t reflect.StructField, o reflect.Value, options tagOptionsMap) (isValid bool, resultErr error) { +func typeCheck(v reflect.Value, t reflect.StructField, o reflect.Value, options tagOptionsMap, p reflect.Value) (isValid bool, resultErr error) { if !v.IsValid() { return false, nil } @@ -1324,10 +1324,15 @@ func typeCheck(v reflect.Value, t reflect.StructField, o reflect.Value, options } if isEmptyValue(v) { - // an empty value is not validated, checks only required - isValid, resultErr = checkRequired(v, t, options) - for key := range options { - delete(options, key) + if p.Kind() == reflect.Slice || p.Kind() == reflect.Array && p.Len() > 0 { + // empty values are allowed for elements of arrays/slices, the parent has already been checked against the zero type + return true, nil + } else { + // an empty value is not validated, checks only required + isValid, resultErr = checkRequired(v, t, options) + for key := range options { + delete(options, key) + } } return isValid, resultErr } @@ -1503,7 +1508,7 @@ func typeCheck(v reflect.Value, t reflect.StructField, o reflect.Value, options var resultItem bool var err error if v.MapIndex(k).Kind() != reflect.Struct { - resultItem, err = typeCheck(v.MapIndex(k), t, o, options) + resultItem, err = typeCheck(v.MapIndex(k), t, o, options, v) if err != nil { return false, err } @@ -1523,7 +1528,7 @@ func typeCheck(v reflect.Value, t reflect.StructField, o reflect.Value, options var resultItem bool var err error if v.Index(i).Kind() != reflect.Struct { - resultItem, err = typeCheck(v.Index(i), t, o, options) + resultItem, err = typeCheck(v.Index(i), t, o, options, v) if err != nil { return false, err } @@ -1548,7 +1553,7 @@ func typeCheck(v reflect.Value, t reflect.StructField, o reflect.Value, options if v.IsNil() { return true, nil } - return typeCheck(v.Elem(), t, o, options) + return typeCheck(v.Elem(), t, o, options, v) case reflect.Struct: return true, nil default: @@ -1563,7 +1568,7 @@ func stripParams(validatorString string) string { // isEmptyValue checks whether value empty or not func isEmptyValue(v reflect.Value) bool { switch v.Kind() { - case reflect.String, reflect.Array: + case reflect.String: return v.Len() == 0 case reflect.Map, reflect.Slice: return v.Len() == 0 || v.IsNil() diff --git a/validator_test.go b/validator_test.go index e624b2c..5e3618f 100644 --- a/validator_test.go +++ b/validator_test.go @@ -2965,6 +2965,7 @@ type testByteMap map[byte]byte type testByteSlice []byte type testStringStringMap map[string]string type testStringIntMap map[string]int +type testIntArray [8]int func TestRequired(t *testing.T) { @@ -3024,6 +3025,14 @@ func TestRequired(t *testing.T) { }, true, }, + { + struct { + TestIntArray testIntArray `valid:"required"` + }{ + testIntArray{0, 1, 2, 3, 4, 5, 6, 7}, + }, + true, + }, { struct { TestByteArray testByteArray `valid:"required"` @@ -3042,7 +3051,7 @@ func TestRequired(t *testing.T) { struct { TestByteArray testByteArray `valid:"required"` }{ - testByteArray{'1', '2', '3', '4', '5', '6', '7', 'A'}, + testByteArray{0x00, '1', '2', '3', '4', '5', '6', '7'}, }, true, },