Merge pull request #42 from bluesuncorp/v5

merge latest changes from v5
pull/58/head
Dean Karn 9 years ago
commit 40c38f9931
  1. 2
      README.md
  2. 125
      baked_in.go
  3. 24
      doc.go
  4. 2
      validator.go
  5. 232
      validator_test.go

@ -1,6 +1,6 @@
Package validator Package validator
================ ================
[![Build Status](https://travis-ci.org/bluesuncorp/validator.svg?branch=v5.0.2)](https://travis-ci.org/bluesuncorp/validator) [![Build Status](https://travis-ci.org/bluesuncorp/validator.svg?branch=v5.1)](https://travis-ci.org/bluesuncorp/validator)
[![GoDoc](https://godoc.org/gopkg.in/bluesuncorp/validator.v5?status.svg)](https://godoc.org/gopkg.in/bluesuncorp/validator.v5) [![GoDoc](https://godoc.org/gopkg.in/bluesuncorp/validator.v5?status.svg)](https://godoc.org/gopkg.in/bluesuncorp/validator.v5)
Package validator implements value validations for structs and individual fields based on tags. Package validator implements value validations for structs and individual fields based on tags.

@ -16,10 +16,14 @@ var BakedInValidators = map[string]Func{
"len": hasLengthOf, "len": hasLengthOf,
"min": hasMinOf, "min": hasMinOf,
"max": hasMaxOf, "max": hasMaxOf,
"eq": isEq,
"ne": isNe,
"lt": isLt, "lt": isLt,
"lte": isLte, "lte": isLte,
"gt": isGt, "gt": isGt,
"gte": isGte, "gte": isGte,
"eqfield": isEqField,
"nefield": isNeField,
"gtefield": isGteField, "gtefield": isGteField,
"gtfield": isGtField, "gtfield": isGtField,
"ltefield": isLteField, "ltefield": isLteField,
@ -40,6 +44,127 @@ var BakedInValidators = map[string]Func{
"base64": isBase64, "base64": isBase64,
} }
func isNeField(top interface{}, current interface{}, field interface{}, param string) bool {
return !isEqField(top, current, field, param)
}
func isNe(top interface{}, current interface{}, field interface{}, param string) bool {
return !isEq(top, current, field, param)
}
func isEqField(top interface{}, current interface{}, field interface{}, param string) bool {
if current == nil {
panic("struct not passed for cross validation")
}
currentVal := reflect.ValueOf(current)
if currentVal.Kind() == reflect.Ptr && !currentVal.IsNil() {
currentVal = reflect.ValueOf(currentVal.Elem().Interface())
}
var currentFielVal reflect.Value
switch currentVal.Kind() {
case reflect.Struct:
if currentVal.Type() == reflect.TypeOf(time.Time{}) {
currentFielVal = currentVal
break
}
f := currentVal.FieldByName(param)
if f.Kind() == reflect.Invalid {
panic(fmt.Sprintf("Field \"%s\" not found in struct", param))
}
currentFielVal = f
default:
currentFielVal = currentVal
}
if currentFielVal.Kind() == reflect.Ptr && !currentFielVal.IsNil() {
currentFielVal = reflect.ValueOf(currentFielVal.Elem().Interface())
}
fv := reflect.ValueOf(field)
switch fv.Kind() {
case reflect.String:
return fv.String() == currentFielVal.String()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return fv.Int() == currentFielVal.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return fv.Uint() == currentFielVal.Uint()
case reflect.Float32, reflect.Float64:
return fv.Float() == currentFielVal.Float()
case reflect.Slice, reflect.Map, reflect.Array:
return int64(fv.Len()) == int64(currentFielVal.Len())
case reflect.Struct:
if fv.Type() == reflect.TypeOf(time.Time{}) {
if currentFielVal.Type() != reflect.TypeOf(time.Time{}) {
panic("Bad Top Level field type")
}
t := currentFielVal.Interface().(time.Time)
fieldTime := field.(time.Time)
return fieldTime.Equal(t)
}
}
panic(fmt.Sprintf("Bad field type %T", field))
}
func isEq(top interface{}, current interface{}, field interface{}, param string) bool {
st := reflect.ValueOf(field)
switch st.Kind() {
case reflect.String:
return st.String() == param
case reflect.Slice, reflect.Map, reflect.Array:
p := asInt(param)
return int64(st.Len()) == p
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
p := asInt(param)
return st.Int() == p
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
p := asUint(param)
return st.Uint() == p
case reflect.Float32, reflect.Float64:
p := asFloat(param)
return st.Float() == p
}
panic(fmt.Sprintf("Bad field type %T", field))
}
func isBase64(top interface{}, current interface{}, field interface{}, param string) bool { func isBase64(top interface{}, current interface{}, field interface{}, param string) bool {
return matchesRegex(base64Regex, field) return matchesRegex(base64Regex, field)
} }

@ -192,6 +192,16 @@ Here is a list of the current built in validators:
the string length is at least that number of characters. For slices, the string length is at least that number of characters. For slices,
arrays, and maps, validates the number of items. (Usage: min=10) arrays, and maps, validates the number of items. (Usage: min=10)
eq
For strings & numbers, eq will ensure that the value is
equal to the parameter given. For slices, arrays, and maps,
validates the number of items. (Usage: eq=10)
ne
For strings & numbers, eq will ensure that the value is not
equal to the parameter given. For slices, arrays, and maps,
validates the number of items. (Usage: eq=10)
gt gt
For numbers, this will ensure that the value is greater than the For numbers, this will ensure that the value is greater than the
parameter given. For strings, it checks that the string length parameter given. For strings, it checks that the string length
@ -221,6 +231,20 @@ Here is a list of the current built in validators:
For time.Time ensures the time value is less than or equal to time.Now.UTC() For time.Time ensures the time value is less than or equal to time.Now.UTC()
(Usage: lte) (Usage: lte)
eqfield
This will validate the field value against another fields value either within
a struct or passed in field.
usage examples are for validation of a password and confirm password:
Validation on Password field using validate.Struct Usage(eqfield=ConfirmPassword)
Validating by field validate.FieldWithValue(password, confirmpassword, "eqfield")
nefield
This will validate the field value against another fields value either within
a struct or passed in field.
usage examples are for ensuring two colors are not the same:
Validation on Color field using validate.Struct Usage(nefield=Color2)
Validating by field validate.FieldWithValue(color1, color2, "nefield")
gtfield gtfield
Only valid for Numbers and time.Time types, this will validate the field value Only valid for Numbers and time.Time types, this will validate the field value
against another fields value either within a struct or passed in field. against another fields value either within a struct or passed in field.

@ -200,7 +200,7 @@ func (v *Validate) structRecursive(top interface{}, current interface{}, s inter
} }
// if no validation and not a struct (which may containt fields for validation) // if no validation and not a struct (which may containt fields for validation)
if tag == "" && valueField.Kind() != reflect.Struct && valueField.Kind() != reflect.Interface { if tag == "" && ((valueField.Kind() != reflect.Struct && valueField.Kind() != reflect.Interface) || valueField.Type() == reflect.TypeOf(time.Time{})) {
continue continue
} }

@ -142,6 +142,238 @@ func isEqualFunc(val interface{}, current interface{}, field interface{}, param
return current.(string) == field.(string) return current.(string) == field.(string)
} }
func (ms *MySuite) TestIsNeFieldValidation(c *C) {
var j uint64
var k float64
s := "abcd"
i := 1
j = 1
k = 1.543
arr := []string{"test"}
now := time.Now().UTC()
var j2 uint64
var k2 float64
s2 := "abcdef"
i2 := 3
j2 = 2
k2 = 1.5434456
arr2 := []string{"test", "test2"}
arr3 := []string{"test"}
now2 := now
err := validate.FieldWithValue(s, s2, "nefield")
c.Assert(err, IsNil)
err = validate.FieldWithValue(i2, i, "nefield")
c.Assert(err, IsNil)
err = validate.FieldWithValue(j2, j, "nefield")
c.Assert(err, IsNil)
err = validate.FieldWithValue(k2, k, "nefield")
c.Assert(err, IsNil)
err = validate.FieldWithValue(arr2, arr, "nefield")
c.Assert(err, IsNil)
err = validate.FieldWithValue(now2, now, "nefield")
c.Assert(err, NotNil)
err = validate.FieldWithValue(arr3, arr, "nefield")
c.Assert(err, NotNil)
type Test struct {
Start *time.Time `validate:"nefield=End"`
End *time.Time
}
sv := &Test{
Start: &now,
End: &now,
}
errs := validate.Struct(sv)
c.Assert(errs, NotNil)
now3 := time.Now().UTC()
sv = &Test{
Start: &now,
End: &now3,
}
errs = validate.Struct(sv)
c.Assert(errs, IsNil)
channel := make(chan string)
c.Assert(func() { validate.FieldWithValue(nil, 1, "nefield") }, PanicMatches, "struct not passed for cross validation")
c.Assert(func() { validate.FieldWithValue(5, channel, "nefield") }, PanicMatches, "Bad field type chan string")
c.Assert(func() { validate.FieldWithValue(5, now, "nefield") }, PanicMatches, "Bad Top Level field type")
type Test2 struct {
Start *time.Time `validate:"nefield=NonExistantField"`
End *time.Time
}
sv2 := &Test2{
Start: &now,
End: &now,
}
c.Assert(func() { validate.Struct(sv2) }, PanicMatches, "Field \"NonExistantField\" not found in struct")
}
func (ms *MySuite) TestIsNeValidation(c *C) {
var j uint64
var k float64
s := "abcdef"
i := 3
j = 2
k = 1.5434
arr := []string{"test"}
now := time.Now().UTC()
err := validate.Field(s, "ne=abcd")
c.Assert(err, IsNil)
err = validate.Field(i, "ne=1")
c.Assert(err, IsNil)
err = validate.Field(j, "ne=1")
c.Assert(err, IsNil)
err = validate.Field(k, "ne=1.543")
c.Assert(err, IsNil)
err = validate.Field(arr, "ne=2")
c.Assert(err, IsNil)
err = validate.Field(arr, "ne=1")
c.Assert(err, NotNil)
c.Assert(func() { validate.Field(now, "ne=now") }, PanicMatches, "Bad field type time.Time")
}
func (ms *MySuite) TestIsEqFieldValidation(c *C) {
var j uint64
var k float64
s := "abcd"
i := 1
j = 1
k = 1.543
arr := []string{"test"}
now := time.Now().UTC()
var j2 uint64
var k2 float64
s2 := "abcd"
i2 := 1
j2 = 1
k2 = 1.543
arr2 := []string{"test"}
arr3 := []string{"test", "test2"}
now2 := now
err := validate.FieldWithValue(s, s2, "eqfield")
c.Assert(err, IsNil)
err = validate.FieldWithValue(i2, i, "eqfield")
c.Assert(err, IsNil)
err = validate.FieldWithValue(j2, j, "eqfield")
c.Assert(err, IsNil)
err = validate.FieldWithValue(k2, k, "eqfield")
c.Assert(err, IsNil)
err = validate.FieldWithValue(arr2, arr, "eqfield")
c.Assert(err, IsNil)
err = validate.FieldWithValue(now2, now, "eqfield")
c.Assert(err, IsNil)
err = validate.FieldWithValue(arr3, arr, "eqfield")
c.Assert(err, NotNil)
type Test struct {
Start *time.Time `validate:"eqfield=End"`
End *time.Time
}
sv := &Test{
Start: &now,
End: &now,
}
errs := validate.Struct(sv)
c.Assert(errs, IsNil)
now3 := time.Now().UTC()
sv = &Test{
Start: &now,
End: &now3,
}
errs = validate.Struct(sv)
c.Assert(errs, NotNil)
channel := make(chan string)
c.Assert(func() { validate.FieldWithValue(nil, 1, "eqfield") }, PanicMatches, "struct not passed for cross validation")
c.Assert(func() { validate.FieldWithValue(5, channel, "eqfield") }, PanicMatches, "Bad field type chan string")
c.Assert(func() { validate.FieldWithValue(5, now, "eqfield") }, PanicMatches, "Bad Top Level field type")
type Test2 struct {
Start *time.Time `validate:"eqfield=NonExistantField"`
End *time.Time
}
sv2 := &Test2{
Start: &now,
End: &now,
}
c.Assert(func() { validate.Struct(sv2) }, PanicMatches, "Field \"NonExistantField\" not found in struct")
}
func (ms *MySuite) TestIsEqValidation(c *C) {
var j uint64
var k float64
s := "abcd"
i := 1
j = 1
k = 1.543
arr := []string{"test"}
now := time.Now().UTC()
err := validate.Field(s, "eq=abcd")
c.Assert(err, IsNil)
err = validate.Field(i, "eq=1")
c.Assert(err, IsNil)
err = validate.Field(j, "eq=1")
c.Assert(err, IsNil)
err = validate.Field(k, "eq=1.543")
c.Assert(err, IsNil)
err = validate.Field(arr, "eq=1")
c.Assert(err, IsNil)
err = validate.Field(arr, "eq=2")
c.Assert(err, NotNil)
c.Assert(func() { validate.Field(now, "eq=now") }, PanicMatches, "Bad field type time.Time")
}
func (ms *MySuite) TestBase64Validation(c *C) { func (ms *MySuite) TestBase64Validation(c *C) {
s := "dW5pY29ybg==" s := "dW5pY29ybg=="

Loading…
Cancel
Save