Update Required & Invalid logic

updated required validator to check for a nil value for types:
slice, map, pointer, interface, channel and function.
updated tranverseField to handle invalid field type.

 Changes to be committed:
	modified:   baked_in.go
	modified:   doc.go
	modified:   validator.go
	modified:   validator_test.go
pull/126/head
joeybloggs 9 years ago
parent ea0db1fa47
commit e078205c78
  1. 6
      baked_in.go
  2. 5
      doc.go
  3. 22
      validator.go
  4. 77
      validator_test.go

@ -403,10 +403,8 @@ func isAlpha(topStruct reflect.Value, currentStruct reflect.Value, field reflect
func hasValue(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { func hasValue(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
switch fieldKind { switch fieldKind {
case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func:
case reflect.Slice, reflect.Map, reflect.Array: return !field.IsNil()
return !field.IsNil() && int64(field.Len()) > 0
default: default:
return field.IsValid() && field.Interface() != reflect.Zero(fieldType).Interface() return field.IsValid() && field.Interface() != reflect.Zero(fieldType).Interface()
} }

@ -123,9 +123,10 @@ Here is a list of the current built in validators:
required will be applied to string required will be applied to string
required 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 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) (Usage: required)
len len

@ -243,12 +243,10 @@ func (v *Validate) traverseField(topStruct reflect.Value, currentStruct reflect.
kind = current.Kind() kind = current.Kind()
} }
typ := current.Type()
// this also allows for tags 'required' and 'omitempty' to be used on // this also allows for tags 'required' and 'omitempty' to be used on
// nested struct fields because when len(tags) > 0 below and the value is nil // nested struct fields because when len(tags) > 0 below and the value is nil
// then required failes and we check for omitempty just before that // then required failes and we check for omitempty just before that
if (kind == reflect.Ptr || kind == reflect.Interface) && current.IsNil() { if ((kind == reflect.Ptr || kind == reflect.Interface) && current.IsNil()) || kind == reflect.Invalid {
if strings.Contains(tag, omitempty) { if strings.Contains(tag, omitempty) {
return return
@ -264,19 +262,35 @@ func (v *Validate) traverseField(topStruct reflect.Value, currentStruct reflect.
param = vals[1] param = vals[1]
} }
if kind == reflect.Invalid {
errs[errPrefix+name] = &FieldError{
Field: name,
Tag: vals[0],
Param: param,
Kind: kind,
}
return
}
errs[errPrefix+name] = &FieldError{ errs[errPrefix+name] = &FieldError{
Field: name, Field: name,
Tag: vals[0], Tag: vals[0],
Param: param, Param: param,
Value: current.Interface(), Value: current.Interface(),
Kind: kind, Kind: kind,
Type: typ, Type: current.Type(),
} }
return return
} }
// if we get here tag length is zero and we can leave
if kind == reflect.Invalid {
return
}
} }
typ := current.Type()
switch kind { switch kind {
case reflect.Struct, reflect.Interface: case reflect.Struct, reflect.Interface:

@ -119,6 +119,79 @@ func AssertError(t *testing.T, errs ValidationErrors, key, field, expectedTag st
EqualSkip(t, 2, val.Tag, expectedTag) 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)
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 TestDatePtrValidationIssueValidation(t *testing.T) { func TestDatePtrValidationIssueValidation(t *testing.T) {
type Test struct { type Test struct {
@ -3262,14 +3335,14 @@ func TestStructSliceValidation(t *testing.T) {
Min: []int{1, 2}, Min: []int{1, 2},
Max: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}, Max: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0},
MinMax: []int{1, 2, 3, 4, 5}, MinMax: []int{1, 2, 3, 4, 5},
OmitEmpty: []int{}, OmitEmpty: nil,
} }
errs := validate.Struct(tSuccess) errs := validate.Struct(tSuccess)
Equal(t, errs, nil) Equal(t, errs, nil)
tFail := &TestSlice{ tFail := &TestSlice{
Required: []int{}, Required: nil,
Len: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1}, Len: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1},
Min: []int{}, Min: []int{},
Max: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1}, Max: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1},

Loading…
Cancel
Save