Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
10 changes: 6 additions & 4 deletions baked_in.go
Original file line number Diff line number Diff line change
Expand Up @@ -424,10 +424,12 @@ func hasValue(top interface{}, current interface{}, field interface{}, param str
st := reflect.ValueOf(field)

switch st.Kind() {

case reflect.Slice, reflect.Map, reflect.Array:
return field != nil && int64(st.Len()) > 0

case reflect.Invalid:
return false
case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func:
return !st.IsNil()
case reflect.Array:
return field != reflect.Zero(reflect.TypeOf(field)).Interface()
default:
return field != nil && field != reflect.Zero(reflect.TypeOf(field)).Interface()
}
Expand Down
5 changes: 3 additions & 2 deletions doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,10 @@ Here is a list of the current built in validators:
within its SliceOrArrayErrs or MapErrs fields.

required
This validates that the value is not the data types default value.
This validates that the value is not the data types default zero value.
For numbers ensures value is not zero. For strings ensures value is
not "". For slices, arrays, and maps, ensures the length is not zero.
not "". For slices, maps, pointers, interfaces, channels and functions
ensures the value is not nil.
(Usage: required)

len
Expand Down
14 changes: 12 additions & 2 deletions validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,11 @@ func (v *Validate) fieldWithNameAndValue(val interface{}, current interface{}, f
f = valueField.Interface()
}

cField = &cachedField{name: name, kind: valueField.Kind(), tag: tag, typ: valueField.Type()}
cField = &cachedField{name: name, kind: valueField.Kind(), tag: tag}

if cField.kind != reflect.Invalid {
cField.typ = valueField.Type()
}

switch cField.kind {
case reflect.Slice, reflect.Array:
Expand All @@ -648,8 +652,14 @@ func (v *Validate) fieldWithNameAndValue(val interface{}, current interface{}, f
}

switch cField.kind {
case reflect.Invalid:
return &FieldError{
Field: cField.name,
Tag: cField.tag,
Kind: cField.kind,
}

case reflect.Struct, reflect.Interface, reflect.Invalid:
case reflect.Struct, reflect.Interface:

if cField.typ != reflect.TypeOf(time.Time{}) {
panic("Invalid field passed to fieldWithNameAndValue")
Expand Down
82 changes: 79 additions & 3 deletions validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,82 @@ func AssertMapFieldError(t *testing.T, s map[string]*FieldError, field string, e
EqualSkip(t, 2, val.Tag, expectedTag)
}

func TestSliceMapArrayChanFuncPtrInterfaceRequiredValidation(t *testing.T) {

var m map[string]string

errs := validate.Field(m, "required")
NotEqual(t, errs, nil)
// AssertError(t, errs, "", "", "required")

m = map[string]string{}
errs = validate.Field(m, "required")
Equal(t, errs, nil)

var arr [5]string
errs = validate.Field(arr, "required")
NotEqual(t, errs, nil)
// AssertError(t, errs, "", "", "required")

arr[0] = "ok"
errs = validate.Field(arr, "required")
Equal(t, errs, nil)

var s []string
errs = validate.Field(s, "required")
NotEqual(t, errs, nil)
// AssertError(t, errs, "", "", "required")

s = []string{}
errs = validate.Field(s, "required")
Equal(t, errs, nil)

var c chan string
errs = validate.Field(c, "required")
NotEqual(t, errs, nil)
// AssertError(t, errs, "", "", "required")

c = make(chan string)
errs = validate.Field(c, "required")
Equal(t, errs, nil)

var tst *int
errs = validate.Field(tst, "required")
NotEqual(t, errs, nil)
// AssertError(t, errs, "", "", "required")

one := 1
tst = &one
errs = validate.Field(tst, "required")
Equal(t, errs, nil)

var iface interface{}

errs = validate.Field(iface, "required")
NotEqual(t, errs, nil)
// AssertError(t, errs, "", "", "required")

errs = validate.Field(iface, "omitempty,required")
Equal(t, errs, nil)

errs = validate.Field(iface, "")
Equal(t, errs, nil)

errs = validate.Field(iface, "len=1")
NotEqual(t, errs, nil)

var f func(string)

errs = validate.Field(f, "required")
NotEqual(t, errs, nil)
// AssertError(t, errs, "", "", "required")

f = func(name string) {}

errs = validate.Field(f, "required")
Equal(t, errs, nil)
}

func TestBadKeyValidation(t *testing.T) {
type Test struct {
Name string `validate:"required, "`
Expand Down Expand Up @@ -3735,14 +3811,14 @@ func TestStructSliceValidation(t *testing.T) {
Min: []int{1, 2},
Max: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0},
MinMax: []int{1, 2, 3, 4, 5},
OmitEmpty: []int{},
OmitEmpty: nil,
}

err := validate.Struct(tSuccess)
Equal(t, err, nil)

tFail := &TestSlice{
Required: []int{},
Required: nil,
Len: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1},
Min: []int{},
Max: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1},
Expand Down Expand Up @@ -3810,7 +3886,7 @@ func TestPoolObjectMaxSizeValidation(t *testing.T) {
Min: []int{1, 2},
Max: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0},
MinMax: []int{1, 2, 3, 4, 5},
OmitEmpty: []int{},
OmitEmpty: nil,
}

for i := 0; i < 2; i++ {
Expand Down