diff --git a/baked_in.go b/baked_in.go index 04c0f76..07c1563 100644 --- a/baked_in.go +++ b/baked_in.go @@ -5,6 +5,7 @@ import ( "net/url" "reflect" "strconv" + "time" ) // BakedInValidators is the map of ValidationFunc used internally @@ -43,9 +44,9 @@ func isURI(val interface{}, field interface{}, param string) bool { _, err := url.ParseRequestURI(field.(string)) return err == nil - default: - panic(fmt.Sprintf("Bad field type %T", field)) } + + panic(fmt.Sprintf("Bad field type %T", field)) } func isURL(val interface{}, field interface{}, param string) bool { @@ -66,10 +67,9 @@ func isURL(val interface{}, field interface{}, param string) bool { } return err == nil - - default: - panic(fmt.Sprintf("Bad field type %T", field)) } + + panic(fmt.Sprintf("Bad field type %T", field)) } func isEmail(val interface{}, field interface{}, param string) bool { @@ -80,9 +80,9 @@ func isEmail(val interface{}, field interface{}, param string) bool { case reflect.String: return emailRegex.MatchString(field.(string)) - default: - panic(fmt.Sprintf("Bad field type %T", field)) } + + panic(fmt.Sprintf("Bad field type %T", field)) } func isHsla(val interface{}, field interface{}, param string) bool { @@ -93,9 +93,9 @@ func isHsla(val interface{}, field interface{}, param string) bool { case reflect.String: return hslaRegex.MatchString(field.(string)) - default: - panic(fmt.Sprintf("Bad field type %T", field)) } + + panic(fmt.Sprintf("Bad field type %T", field)) } func isHsl(val interface{}, field interface{}, param string) bool { @@ -106,9 +106,9 @@ func isHsl(val interface{}, field interface{}, param string) bool { case reflect.String: return hslRegex.MatchString(field.(string)) - default: - panic(fmt.Sprintf("Bad field type %T", field)) } + + panic(fmt.Sprintf("Bad field type %T", field)) } func isRgba(val interface{}, field interface{}, param string) bool { @@ -119,9 +119,9 @@ func isRgba(val interface{}, field interface{}, param string) bool { case reflect.String: return rgbaRegex.MatchString(field.(string)) - default: - panic(fmt.Sprintf("Bad field type %T", field)) } + + panic(fmt.Sprintf("Bad field type %T", field)) } func isRgb(val interface{}, field interface{}, param string) bool { @@ -132,9 +132,9 @@ func isRgb(val interface{}, field interface{}, param string) bool { case reflect.String: return rgbRegex.MatchString(field.(string)) - default: - panic(fmt.Sprintf("Bad field type %T", field)) } + + panic(fmt.Sprintf("Bad field type %T", field)) } func isHexcolor(val interface{}, field interface{}, param string) bool { @@ -145,9 +145,9 @@ func isHexcolor(val interface{}, field interface{}, param string) bool { case reflect.String: return hexcolorRegex.MatchString(field.(string)) - default: - panic(fmt.Sprintf("Bad field type %T", field)) } + + panic(fmt.Sprintf("Bad field type %T", field)) } func isHexadecimal(val interface{}, field interface{}, param string) bool { @@ -158,9 +158,9 @@ func isHexadecimal(val interface{}, field interface{}, param string) bool { case reflect.String: return hexadecimalRegex.MatchString(field.(string)) - default: - panic(fmt.Sprintf("Bad field type %T", field)) } + + panic(fmt.Sprintf("Bad field type %T", field)) } func isNumber(val interface{}, field interface{}, param string) bool { @@ -171,9 +171,9 @@ func isNumber(val interface{}, field interface{}, param string) bool { case reflect.String: return numberRegex.MatchString(field.(string)) - default: - panic(fmt.Sprintf("Bad field type %T", field)) } + + panic(fmt.Sprintf("Bad field type %T", field)) } func isNumeric(val interface{}, field interface{}, param string) bool { @@ -184,9 +184,9 @@ func isNumeric(val interface{}, field interface{}, param string) bool { case reflect.String: return numericRegex.MatchString(field.(string)) - default: - panic(fmt.Sprintf("Bad field type %T", field)) } + + panic(fmt.Sprintf("Bad field type %T", field)) } func isAlphanum(val interface{}, field interface{}, param string) bool { @@ -197,9 +197,9 @@ func isAlphanum(val interface{}, field interface{}, param string) bool { case reflect.String: return alphaNumericRegex.MatchString(field.(string)) - default: - panic(fmt.Sprintf("Bad field type %T", field)) } + + panic(fmt.Sprintf("Bad field type %T", field)) } func isAlpha(val interface{}, field interface{}, param string) bool { @@ -210,9 +210,9 @@ func isAlpha(val interface{}, field interface{}, param string) bool { case reflect.String: return alphaRegex.MatchString(field.(string)) - default: - panic(fmt.Sprintf("Bad field type %T", field)) } + + panic(fmt.Sprintf("Bad field type %T", field)) } func hasValue(val interface{}, field interface{}, param string) bool { @@ -260,9 +260,18 @@ func isGte(val interface{}, field interface{}, param string) bool { return st.Float() >= p - default: - panic(fmt.Sprintf("Bad field type %T", field)) + case reflect.Struct: + + if st.Type() == reflect.TypeOf(field) { + + now := time.Now().UTC() + t := field.(time.Time) + + return t.After(now) || t.Equal(now) + } } + + panic(fmt.Sprintf("Bad field type %T", field)) } func isGt(val interface{}, field interface{}, param string) bool { @@ -295,10 +304,15 @@ func isGt(val interface{}, field interface{}, param string) bool { p := asFloat(param) return st.Float() > p + case reflect.Struct: - default: - panic(fmt.Sprintf("Bad field type %T", field)) + if st.Type() == reflect.TypeOf(field) { + + return field.(time.Time).After(time.Now().UTC()) + } } + + panic(fmt.Sprintf("Bad field type %T", field)) } // length tests whether a variable's length is equal to a given @@ -334,10 +348,9 @@ func hasLengthOf(val interface{}, field interface{}, param string) bool { p := asFloat(param) return st.Float() == p - - default: - panic(fmt.Sprintf("Bad field type %T", field)) } + + panic(fmt.Sprintf("Bad field type %T", field)) } // min tests whether a variable value is larger or equal to a given @@ -380,9 +393,18 @@ func isLte(val interface{}, field interface{}, param string) bool { return st.Float() <= p - default: - panic(fmt.Sprintf("Bad field type %T", field)) + case reflect.Struct: + + if st.Type() == reflect.TypeOf(field) { + + now := time.Now().UTC() + t := field.(time.Time) + + return t.Before(now) || t.Equal(now) + } } + + panic(fmt.Sprintf("Bad field type %T", field)) } func isLt(val interface{}, field interface{}, param string) bool { @@ -416,9 +438,15 @@ func isLt(val interface{}, field interface{}, param string) bool { return st.Float() < p - default: - panic(fmt.Sprintf("Bad field type %T", field)) + case reflect.Struct: + + if st.Type() == reflect.TypeOf(field) { + + return field.(time.Time).Before(time.Now().UTC()) + } } + + panic(fmt.Sprintf("Bad field type %T", field)) } // max tests whether a variable value is lesser than a given diff --git a/validator.go b/validator.go index 18316f2..125799b 100644 --- a/validator.go +++ b/validator.go @@ -13,6 +13,7 @@ import ( "fmt" "reflect" "strings" + "time" "unicode" ) @@ -174,75 +175,6 @@ func (v *Validator) ValidateStruct(s interface{}) *StructValidationErrors { } return v.validateStructRecursive(s, s) - // structValue := reflect.ValueOf(s) - // structType := reflect.TypeOf(s) - // structName := structType.Name() - - // validationErrors := &StructValidationErrors{ - // Struct: structName, - // Errors: map[string]*FieldValidationError{}, - // StructErrors: map[string]*StructValidationErrors{}, - // } - - // if structValue.Kind() == reflect.Ptr && !structValue.IsNil() { - // return v.ValidateStruct(structValue.Elem().Interface()) - // } - - // if structValue.Kind() != reflect.Struct && structValue.Kind() != reflect.Interface { - // panic("interface passed for validation is not a struct") - // } - - // var numFields = structValue.NumField() - - // for i := 0; i < numFields; i++ { - - // valueField := structValue.Field(i) - // typeField := structType.Field(i) - - // if valueField.Kind() == reflect.Ptr && !valueField.IsNil() { - // valueField = valueField.Elem() - // } - - // tag := typeField.Tag.Get(v.tagName) - - // if tag == "-" { - // continue - // } - - // // if no validation and not a struct (which may containt fields for validation) - // if tag == "" && valueField.Kind() != reflect.Struct && valueField.Kind() != reflect.Interface { - // continue - // } - - // switch valueField.Kind() { - - // case reflect.Struct, reflect.Interface: - - // if !unicode.IsUpper(rune(typeField.Name[0])) { - // continue - // } - - // if structErrors := v.ValidateStruct(valueField.Interface()); structErrors != nil { - // validationErrors.StructErrors[typeField.Name] = structErrors - // // free up memory map no longer needed - // structErrors = nil - // } - - // default: - - // if fieldError := v.validateFieldByNameAndTag(valueField.Interface(), typeField.Name, tag); fieldError != nil { - // validationErrors.Errors[fieldError.Field] = fieldError - // // free up memory reference - // fieldError = nil - // } - // } - // } - - // if len(validationErrors.Errors) == 0 && len(validationErrors.StructErrors) == 0 { - // return nil - // } - - // return validationErrors } // validateStructRecursive validates a struct recursivly and passes the top level struct around for use in validator functions and returns a struct containing the errors @@ -296,10 +228,21 @@ func (v *Validator) validateStructRecursive(top interface{}, s interface{}) *Str continue } - if structErrors := v.validateStructRecursive(top, valueField.Interface()); structErrors != nil { - validationErrors.StructErrors[typeField.Name] = structErrors - // free up memory map no longer needed - structErrors = nil + if valueField.Type() == reflect.TypeOf(time.Time{}) { + + if fieldError := v.validateFieldByNameAndTagAndValue(top, valueField.Interface(), typeField.Name, tag); fieldError != nil { + validationErrors.Errors[fieldError.Field] = fieldError + // free up memory reference + fieldError = nil + } + + } else { + + if structErrors := v.ValidateStruct(valueField.Interface()); structErrors != nil { + validationErrors.StructErrors[typeField.Name] = structErrors + // free up memory map no longer needed + structErrors = nil + } } default: @@ -363,7 +306,10 @@ func (v *Validator) validateFieldByNameAndTagAndValue(val interface{}, f interfa switch valueField.Kind() { case reflect.Struct, reflect.Interface, reflect.Invalid: - panic("Invalid field passed to ValidateFieldWithTag") + + if valueField.Type() != reflect.TypeOf(time.Time{}) { + panic("Invalid field passed to ValidateFieldWithTag") + } } var valErr *FieldValidationError diff --git a/validator_test.go b/validator_test.go index 3b2e390..ff734fa 100644 --- a/validator_test.go +++ b/validator_test.go @@ -3,6 +3,7 @@ package validator_test import ( "fmt" "testing" + "time" "github.com/joeybloggs/go-validate-yourself" . "gopkg.in/check.v1" @@ -242,12 +243,70 @@ func (ms *MySuite) TestIsGt(c *C) { i := true c.Assert(func() { validator.ValidateFieldByTag(i, "gt") }, PanicMatches, "Bad field type bool") + + t := time.Now().UTC() + t = t.Add(time.Hour * 24) + + err = validator.ValidateFieldByTag(t, "gt") + c.Assert(err, IsNil) + + t2 := time.Now().UTC() + + err = validator.ValidateFieldByTag(t2, "gt") + c.Assert(err, NotNil) + c.Assert(err.ErrorTag, Equals, "gt") + + type Test struct { + Now *time.Time `validate:"gt"` + } + s := &Test{ + Now: &t, + } + + errs := validator.ValidateStruct(s) + c.Assert(errs, IsNil) + + s = &Test{ + Now: &t2, + } + + errs = validator.ValidateStruct(s) + c.Assert(errs, NotNil) } func (ms *MySuite) TestIsGte(c *C) { i := true c.Assert(func() { validator.ValidateFieldByTag(i, "gte") }, PanicMatches, "Bad field type bool") + + t := time.Now().UTC() + t = t.Add(time.Hour * 24) + + err := validator.ValidateFieldByTag(t, "gte") + c.Assert(err, IsNil) + + t2 := time.Now().UTC() + + err = validator.ValidateFieldByTag(t2, "gte") + c.Assert(err, NotNil) + c.Assert(err.ErrorTag, Equals, "gte") + + type Test struct { + Now *time.Time `validate:"gte"` + } + s := &Test{ + Now: &t, + } + + errs := validator.ValidateStruct(s) + c.Assert(errs, IsNil) + + s = &Test{ + Now: &t2, + } + + errs = validator.ValidateStruct(s) + c.Assert(errs, NotNil) } func (ms *MySuite) TestIsLt(c *C) { @@ -266,12 +325,72 @@ func (ms *MySuite) TestIsLt(c *C) { i := true c.Assert(func() { validator.ValidateFieldByTag(i, "lt") }, PanicMatches, "Bad field type bool") + + t := time.Now().UTC() + + err = validator.ValidateFieldByTag(t, "lt") + c.Assert(err, IsNil) + + t2 := time.Now().UTC() + t2 = t2.Add(time.Hour * 24) + + err = validator.ValidateFieldByTag(t2, "lt") + c.Assert(err, NotNil) + c.Assert(err.ErrorTag, Equals, "lt") + + type Test struct { + Now *time.Time `validate:"lt"` + } + + s := &Test{ + Now: &t, + } + + errs := validator.ValidateStruct(s) + c.Assert(errs, IsNil) + + s = &Test{ + Now: &t2, + } + + errs = validator.ValidateStruct(s) + c.Assert(errs, NotNil) } func (ms *MySuite) TestIsLte(c *C) { i := true c.Assert(func() { validator.ValidateFieldByTag(i, "lte") }, PanicMatches, "Bad field type bool") + + t := time.Now().UTC() + + err := validator.ValidateFieldByTag(t, "lte") + c.Assert(err, IsNil) + + t2 := time.Now().UTC() + t2 = t2.Add(time.Hour * 24) + + err = validator.ValidateFieldByTag(t2, "lte") + c.Assert(err, NotNil) + c.Assert(err.ErrorTag, Equals, "lte") + + type Test struct { + Now *time.Time `validate:"lte"` + } + + s := &Test{ + Now: &t, + } + + errs := validator.ValidateStruct(s) + c.Assert(errs, IsNil) + + s = &Test{ + Now: &t2, + } + + errs = validator.ValidateStruct(s) + c.Assert(errs, NotNil) } func (ms *MySuite) TestUrl(c *C) {