Merge pull request #36 from joeybloggs/v5-development

add eq baked in function + tests
pull/37/head
Dean Karn 10 years ago
commit 1a0a2f52c4
  1. 115
      baked_in.go
  2. 12
      doc.go
  3. 2
      validator.go
  4. 116
      validator_test.go

@ -16,10 +16,12 @@ var BakedInValidators = map[string]Func{
"len": hasLengthOf, "len": hasLengthOf,
"min": hasMinOf, "min": hasMinOf,
"max": hasMaxOf, "max": hasMaxOf,
"eq": isEq,
"lt": isLt, "lt": isLt,
"lte": isLte, "lte": isLte,
"gt": isGt, "gt": isGt,
"gte": isGte, "gte": isGte,
"eqfield": isEqField,
"gtefield": isGteField, "gtefield": isGteField,
"gtfield": isGtField, "gtfield": isGtField,
"ltefield": isLteField, "ltefield": isLteField,
@ -40,6 +42,119 @@ var BakedInValidators = map[string]Func{
"base64": isBase64, "base64": isBase64,
} }
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,11 @@ 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)
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 +226,13 @@ 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")
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,122 @@ func isEqualFunc(val interface{}, current interface{}, field interface{}, param
return current.(string) == field.(string) return current.(string) == field.(string)
} }
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