code coverage back to 100% + some code cleanup

pull/256/head
joeybloggs 8 years ago
parent 2fe87f7a8d
commit 8c60a612c5
  1. 25
      cache.go
  2. 7
      struct_level.go
  3. 4
      validator.go
  4. 24
      validator_instance.go
  5. 233
      validator_test.go

@ -17,7 +17,6 @@ const (
typeStructOnly typeStructOnly
typeDive typeDive
typeOr typeOr
typeExists
) )
const ( const (
@ -25,10 +24,6 @@ const (
undefinedValidation = "Undefined validation function '%s' on field '%s'" undefinedValidation = "Undefined validation function '%s' on field '%s'"
) )
// var (
// validatable = reflect.TypeOf((*Validatable)(nil)).Elem()
// )
type structCache struct { type structCache struct {
lock sync.Mutex lock sync.Mutex
m atomic.Value // map[reflect.Type]*cStruct m atomic.Value // map[reflect.Type]*cStruct
@ -114,26 +109,6 @@ func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStr
cs = &cStruct{Name: sName, fields: make(map[int]*cField), fn: v.structLevelFuncs[typ]} cs = &cStruct{Name: sName, fields: make(map[int]*cField), fn: v.structLevelFuncs[typ]}
// newVal := reflect.New(typ)
// // fmt.Println("implements:", reflect.PtrTo(typ).Implements(validatable))
// tv1, tv2 := newVal.Interface().(Validatable)
// // tv1, tv2 := reflect.PtrTo(typ).Elem().(Validatable)
// fmt.Println("implements2:", tv1, tv2)
// // fmt.Println("Testing if Validatable", tv1, tv2, reflect.PtrTo(typ), current, current.Type(), typ)
// if vable, ok := reflect.New(typ).Interface().(Validatable); ok {
// // fmt.Println("Validatable", cs.fn)
// if cs.fn != nil {
// log.Println("warning: struct level validation overriding 'Validatabe' interface function")
// } else {
// cs.fn = vable.Validate
// // fmt.Println(cs.fn)
// }
// }
numFields := current.NumField() numFields := current.NumField()
var ctag *cTag var ctag *cTag

@ -159,10 +159,3 @@ func (v *validate) ReportValidationErrors(relativeNamespace, relativeStructNames
v.errs = append(v.errs, err) v.errs = append(v.errs, err)
} }
} }
// Validatable is the interface a struct can implement and
// be validated just like registering a StructLevel validation
// (they actually have the exact same signature.)
type Validatable interface {
Validate(sl StructLevel)
}

@ -180,10 +180,6 @@ OUTER:
switch ct.typeof { switch ct.typeof {
case typeExists:
ct = ct.next
continue
case typeOmitEmpty: case typeOmitEmpty:
// set Field Level fields // set Field Level fields

@ -200,10 +200,8 @@ func (v *Validate) Struct(s interface{}) (err error) {
val = val.Elem() val = val.Elem()
} }
typ := val.Type() if val.Kind() != reflect.Struct || val.Type() == timeType {
return &InvalidValidationError{Type: reflect.TypeOf(s)}
if val.Kind() != reflect.Struct || typ == timeType {
return &InvalidValidationError{Type: typ}
} }
// good to validate // good to validate
@ -212,7 +210,7 @@ func (v *Validate) Struct(s interface{}) (err error) {
vd.isPartial = false vd.isPartial = false
// vd.hasExcludes = false // only need to reset in StructPartial and StructExcept // vd.hasExcludes = false // only need to reset in StructPartial and StructExcept
vd.validateStruct(top, val, typ, vd.ns[0:0], vd.actualNs[0:0], nil) vd.validateStruct(top, val, val.Type(), vd.ns[0:0], vd.actualNs[0:0], nil)
if len(vd.errs) > 0 { if len(vd.errs) > 0 {
err = vd.errs err = vd.errs
@ -239,10 +237,8 @@ func (v *Validate) StructPartial(s interface{}, fields ...string) (err error) {
val = val.Elem() val = val.Elem()
} }
typ := val.Type() if val.Kind() != reflect.Struct || val.Type() == timeType {
return &InvalidValidationError{Type: reflect.TypeOf(s)}
if val.Kind() != reflect.Struct || typ == timeType {
return &InvalidValidationError{Type: typ}
} }
// good to validate // good to validate
@ -252,6 +248,7 @@ func (v *Validate) StructPartial(s interface{}, fields ...string) (err error) {
vd.hasExcludes = false vd.hasExcludes = false
vd.includeExclude = make(map[string]struct{}) vd.includeExclude = make(map[string]struct{})
typ := val.Type()
name := typ.Name() name := typ.Name()
if fields != nil { if fields != nil {
@ -316,10 +313,8 @@ func (v *Validate) StructExcept(s interface{}, fields ...string) (err error) {
val = val.Elem() val = val.Elem()
} }
typ := val.Type() if val.Kind() != reflect.Struct || val.Type() == timeType {
return &InvalidValidationError{Type: reflect.TypeOf(s)}
if val.Kind() != reflect.Struct || typ == timeType {
return &InvalidValidationError{Type: typ}
} }
// good to validate // good to validate
@ -329,6 +324,7 @@ func (v *Validate) StructExcept(s interface{}, fields ...string) (err error) {
vd.hasExcludes = true vd.hasExcludes = true
vd.includeExclude = make(map[string]struct{}) vd.includeExclude = make(map[string]struct{})
typ := val.Type()
name := typ.Name() name := typ.Name()
for _, key := range fields { for _, key := range fields {
@ -347,8 +343,6 @@ func (v *Validate) StructExcept(s interface{}, fields ...string) (err error) {
return return
} }
// func (v *validate) traverseField(parent reflect.Value, current reflect.Value, ns []byte, actualNs []byte, cf *cField, ct *cTag) {
// Var validates a single variable using tag style validation. // Var validates a single variable using tag style validation.
// eg. // eg.
// var i int // var i int

@ -304,85 +304,43 @@ type TestStructReturnValidationErrors struct {
Inner1 *TestStructReturnValidationErrorsInner1 `json:"Inner1JSON"` Inner1 *TestStructReturnValidationErrorsInner1 `json:"Inner1JSON"`
} }
// type TestValidatablePtr struct { type StructLevelInvalidErr struct {
// Value string Value string
// } }
// func (tv *TestValidatablePtr) Validate(sl StructLevel) {
// fmt.Printf("HERE *********** %p %#v\n", tv, tv)
// if len(tv.Value) == 0 {
// sl.ReportError(reflect.ValueOf(tv.Value), "Value", "Value", "required")
// }
// }
// type TestValidatableNoPtr struct {
// Value string
// }
// func (tv TestValidatableNoPtr) Validate(sl StructLevel) {
// fmt.Println("HERE2 ***********")
// if len(tv.Value) == 0 {
// sl.ReportError(reflect.ValueOf(tv.Value), "Value", "Value", "required")
// }
// }
// var _ Validatable = new(TestValidatablePtr)
// func TestStructLevelValidatableInterfaceValidations(t *testing.T) {
// // validate := New()
// // tv := &TestValidatablePtr{Value: "tst3"}
// // fmt.Println("VALIDATING***************")
// // err := validate.Struct(tv)
// // NotEqual(t, err, nil)
// // var tv2 TestValidatableNoPtr
// // fmt.Println("VALIDATING***************")
// // err = validate.Struct(tv2)
// // NotEqual(t, err, nil)
// // tv3 := &TestValidatablePtr{Value: "test"}
// // fmt.Println("VALIDATING***************")
// // err = validate.Struct(tv3)
// // Equal(t, err, nil)
// // v1 := New() func StructLevelInvalidError(sl StructLevel) {
// // v1.RegisterStructValidation(StructValidationTestStruct, TestStruct{})
// // tst := &TestStruct{ top := sl.Top().Interface().(StructLevelInvalidErr)
// // String: "good value", s := sl.Current().Interface().(StructLevelInvalidErr)
// // }
// // errs := v1.Struct(tst) if top.Value == s.Value {
// // NotEqual(t, errs, nil) sl.ReportError(nil, "Value", "Value", "required")
// // AssertError(t, errs, "TestStruct.StringVal", "TestStruct.String", "StringVal", "String", "badvalueteststruct") }
}
// // v2 := New() func TestStructLevelInvalidError(t *testing.T) {
// // v2.RegisterStructValidation(StructValidationNoTestStructCustomName, TestStruct{})
// // errs = v2.Struct(tst) validate := New()
// // NotEqual(t, errs, nil) validate.RegisterStructValidation(StructLevelInvalidError, StructLevelInvalidErr{})
// // AssertError(t, errs, "TestStruct.String", "TestStruct.String", "String", "String", "badvalueteststruct")
// // v3 := New() var test StructLevelInvalidErr
// // v3.RegisterStructValidation(StructValidationTestStructInvalid, TestStruct{})
// // errs = v3.Struct(tst) err := validate.Struct(test)
// // NotEqual(t, errs, nil) NotEqual(t, err, nil)
// // AssertError(t, errs, "TestStruct.StringVal", "TestStruct.String", "StringVal", "String", "badvalueteststruct")
// // v4 := New() errs, ok := err.(ValidationErrors)
// // v4.RegisterStructValidation(StructValidationTestStructSuccess, TestStruct{}) Equal(t, ok, true)
// // errs = v4.Struct(tst) fe := errs[0]
// // Equal(t, errs, nil) Equal(t, fe.Field(), "Value")
// } Equal(t, fe.StructField(), "Value")
Equal(t, fe.Namespace(), "StructLevelInvalidErr.Value")
Equal(t, fe.StructNamespace(), "StructLevelInvalidErr.Value")
Equal(t, fe.Tag(), "required")
Equal(t, fe.ActualTag(), "required")
Equal(t, fe.Kind(), reflect.Invalid)
Equal(t, fe.Type(), reflect.TypeOf(nil))
}
func TestNameNamespace(t *testing.T) { func TestNameNamespace(t *testing.T) {
@ -1041,6 +999,24 @@ func TestCrossStructLteFieldValidation(t *testing.T) {
AssertError(t, errs, "Test.Uint", "Test.Uint", "Uint", "Uint", "ltecsfield") AssertError(t, errs, "Test.Uint", "Test.Uint", "Uint", "Uint", "ltecsfield")
AssertError(t, errs, "Test.Float", "Test.Float", "Float", "Float", "ltecsfield") AssertError(t, errs, "Test.Float", "Test.Float", "Float", "Float", "ltecsfield")
AssertError(t, errs, "Test.Array", "Test.Array", "Array", "Array", "ltecsfield") AssertError(t, errs, "Test.Array", "Test.Array", "Array", "Array", "ltecsfield")
type Other struct {
Value string
}
type Test2 struct {
Value Other
Time time.Time `validate:"ltecsfield=Value"`
}
tst := Test2{
Value: Other{Value: "StringVal"},
Time: then,
}
errs = validate.Struct(tst)
NotEqual(t, errs, nil)
AssertError(t, errs, "Test2.Time", "Test2.Time", "Time", "Time", "ltecsfield")
} }
func TestCrossStructLtFieldValidation(t *testing.T) { func TestCrossStructLtFieldValidation(t *testing.T) {
@ -1119,6 +1095,24 @@ func TestCrossStructLtFieldValidation(t *testing.T) {
AssertError(t, errs, "Test.Uint", "Test.Uint", "Uint", "Uint", "ltcsfield") AssertError(t, errs, "Test.Uint", "Test.Uint", "Uint", "Uint", "ltcsfield")
AssertError(t, errs, "Test.Float", "Test.Float", "Float", "Float", "ltcsfield") AssertError(t, errs, "Test.Float", "Test.Float", "Float", "Float", "ltcsfield")
AssertError(t, errs, "Test.Array", "Test.Array", "Array", "Array", "ltcsfield") AssertError(t, errs, "Test.Array", "Test.Array", "Array", "Array", "ltcsfield")
type Other struct {
Value string
}
type Test2 struct {
Value Other
Time time.Time `validate:"ltcsfield=Value"`
}
tst := Test2{
Value: Other{Value: "StringVal"},
Time: then,
}
errs = validate.Struct(tst)
NotEqual(t, errs, nil)
AssertError(t, errs, "Test2.Time", "Test2.Time", "Time", "Time", "ltcsfield")
} }
func TestCrossStructGteFieldValidation(t *testing.T) { func TestCrossStructGteFieldValidation(t *testing.T) {
@ -1209,6 +1203,24 @@ func TestCrossStructGteFieldValidation(t *testing.T) {
AssertError(t, errs, "Test.Uint", "Test.Uint", "Uint", "Uint", "gtecsfield") AssertError(t, errs, "Test.Uint", "Test.Uint", "Uint", "Uint", "gtecsfield")
AssertError(t, errs, "Test.Float", "Test.Float", "Float", "Float", "gtecsfield") AssertError(t, errs, "Test.Float", "Test.Float", "Float", "Float", "gtecsfield")
AssertError(t, errs, "Test.Array", "Test.Array", "Array", "Array", "gtecsfield") AssertError(t, errs, "Test.Array", "Test.Array", "Array", "Array", "gtecsfield")
type Other struct {
Value string
}
type Test2 struct {
Value Other
Time time.Time `validate:"gtecsfield=Value"`
}
tst := Test2{
Value: Other{Value: "StringVal"},
Time: then,
}
errs = validate.Struct(tst)
NotEqual(t, errs, nil)
AssertError(t, errs, "Test2.Time", "Test2.Time", "Time", "Time", "gtecsfield")
} }
func TestCrossStructGtFieldValidation(t *testing.T) { func TestCrossStructGtFieldValidation(t *testing.T) {
@ -1287,6 +1299,24 @@ func TestCrossStructGtFieldValidation(t *testing.T) {
AssertError(t, errs, "Test.Uint", "Test.Uint", "Uint", "Uint", "gtcsfield") AssertError(t, errs, "Test.Uint", "Test.Uint", "Uint", "Uint", "gtcsfield")
AssertError(t, errs, "Test.Float", "Test.Float", "Float", "Float", "gtcsfield") AssertError(t, errs, "Test.Float", "Test.Float", "Float", "Float", "gtcsfield")
AssertError(t, errs, "Test.Array", "Test.Array", "Array", "Array", "gtcsfield") AssertError(t, errs, "Test.Array", "Test.Array", "Array", "Array", "gtcsfield")
type Other struct {
Value string
}
type Test2 struct {
Value Other
Time time.Time `validate:"gtcsfield=Value"`
}
tst := Test2{
Value: Other{Value: "StringVal"},
Time: then,
}
errs = validate.Struct(tst)
NotEqual(t, errs, nil)
AssertError(t, errs, "Test2.Time", "Test2.Time", "Time", "Time", "gtcsfield")
} }
func TestCrossStructNeFieldValidation(t *testing.T) { func TestCrossStructNeFieldValidation(t *testing.T) {
@ -4028,6 +4058,23 @@ func TestIsNeFieldValidation(t *testing.T) {
errs = validate.Struct(sv2) errs = validate.Struct(sv2)
Equal(t, errs, nil) Equal(t, errs, nil)
type Other struct {
Value string
}
type Test3 struct {
Value Other
Time time.Time `validate:"nefield=Value"`
}
tst := Test3{
Value: Other{Value: "StringVal"},
Time: now,
}
errs = validate.Struct(tst)
Equal(t, errs, nil)
} }
func TestIsNeValidation(t *testing.T) { func TestIsNeValidation(t *testing.T) {
@ -4465,6 +4512,24 @@ func TestGtField(t *testing.T) {
errs = validate.Struct(timeTest2) errs = validate.Struct(timeTest2)
NotEqual(t, errs, nil) NotEqual(t, errs, nil)
AssertError(t, errs, "TimeTest2.End", "TimeTest2.End", "End", "End", "gtfield") AssertError(t, errs, "TimeTest2.End", "TimeTest2.End", "End", "End", "gtfield")
type Other struct {
Value string
}
type Test struct {
Value Other
Time time.Time `validate:"gtfield=Value"`
}
tst := Test{
Value: Other{Value: "StringVal"},
Time: end,
}
errs = validate.Struct(tst)
NotEqual(t, errs, nil)
AssertError(t, errs, "Test.Time", "Test.Time", "Time", "Time", "gtfield")
} }
func TestLtField(t *testing.T) { func TestLtField(t *testing.T) {
@ -6093,6 +6158,22 @@ func TestStructSliceValidation(t *testing.T) {
AssertError(t, errs, "TestSlice.Max", "TestSlice.Max", "Max", "Max", "max") AssertError(t, errs, "TestSlice.Max", "TestSlice.Max", "Max", "Max", "max")
AssertError(t, errs, "TestSlice.MinMax", "TestSlice.MinMax", "MinMax", "MinMax", "min") AssertError(t, errs, "TestSlice.MinMax", "TestSlice.MinMax", "MinMax", "MinMax", "min")
AssertError(t, errs, "TestSlice.OmitEmpty", "TestSlice.OmitEmpty", "OmitEmpty", "OmitEmpty", "max") AssertError(t, errs, "TestSlice.OmitEmpty", "TestSlice.OmitEmpty", "OmitEmpty", "OmitEmpty", "max")
fe := getError(errs, "TestSlice.Len", "TestSlice.Len")
NotEqual(t, fe, nil)
Equal(t, fe.Field(), "Len")
Equal(t, fe.StructField(), "Len")
Equal(t, fe.Namespace(), "TestSlice.Len")
Equal(t, fe.StructNamespace(), "TestSlice.Len")
Equal(t, fe.Tag(), "len")
Equal(t, fe.ActualTag(), "len")
Equal(t, fe.Param(), "10")
Equal(t, fe.Kind(), reflect.Slice)
Equal(t, fe.Type(), reflect.TypeOf([]int{}))
_, ok := fe.Value().([]int)
Equal(t, ok, true)
} }
func TestInvalidStruct(t *testing.T) { func TestInvalidStruct(t *testing.T) {
@ -6106,6 +6187,18 @@ func TestInvalidStruct(t *testing.T) {
err := validate.Struct(s.Test) err := validate.Struct(s.Test)
NotEqual(t, err, nil) NotEqual(t, err, nil)
Equal(t, err.Error(), "validator: (nil string)") Equal(t, err.Error(), "validator: (nil string)")
err = validate.Struct(nil)
NotEqual(t, err, nil)
Equal(t, err.Error(), "validator: (nil)")
err = validate.StructPartial(nil, "SubTest.Test")
NotEqual(t, err, nil)
Equal(t, err.Error(), "validator: (nil)")
err = validate.StructExcept(nil, "SubTest.Test")
NotEqual(t, err, nil)
Equal(t, err.Error(), "validator: (nil)")
} }
func TestInvalidValidatorFunction(t *testing.T) { func TestInvalidValidatorFunction(t *testing.T) {

Loading…
Cancel
Save