Skip to content

Commit

Permalink
Merge pull request #127 from bluesuncorp/v6-development
Browse files Browse the repository at this point in the history
Update Required & Invalid logic
  • Loading branch information
Dean Karn authored and Dean Karn committed Jul 27, 2015
2 parents 54927e9 + a563180 commit c000117
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 12 deletions.
6 changes: 2 additions & 4 deletions baked_in.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

switch fieldKind {

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

case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func:
return !field.IsNil()
default:
return field.IsValid() && field.Interface() != reflect.Zero(fieldType).Interface()
}
Expand Down
5 changes: 3 additions & 2 deletions doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,10 @@ Here is a list of the current built in validators:
required will be applied to string
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
22 changes: 18 additions & 4 deletions validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,12 +243,10 @@ func (v *Validate) traverseField(topStruct reflect.Value, currentStruct reflect.
kind = current.Kind()
}

typ := current.Type()

// 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
// 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) {
return
Expand All @@ -264,19 +262,35 @@ func (v *Validate) traverseField(topStruct reflect.Value, currentStruct reflect.
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{
Field: name,
Tag: vals[0],
Param: param,
Value: current.Interface(),
Kind: kind,
Type: typ,
Type: current.Type(),
}

return
}
// if we get here tag length is zero and we can leave
if kind == reflect.Invalid {
return
}
}

typ := current.Type()

switch kind {
case reflect.Struct, reflect.Interface:

Expand Down
77 changes: 75 additions & 2 deletions validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,79 @@ func AssertError(t *testing.T, errs ValidationErrors, key, field, expectedTag st
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) {

type Test struct {
Expand Down Expand Up @@ -3262,14 +3335,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,
}

errs := validate.Struct(tSuccess)
Equal(t, errs, 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

0 comments on commit c000117

Please sign in to comment.