From dcdfaf36f189478a03bcf1ef5e8fcd9fb95a946a Mon Sep 17 00:00:00 2001 From: miraclesu Date: Sun, 28 Jul 2013 16:59:35 +0800 Subject: [PATCH 1/2] Accept parameters more types --- validation/validation.go | 55 ++++++++++++++++++----------------- validation/validation_test.go | 4 +-- validation/validators.go | 3 +- 3 files changed, 32 insertions(+), 30 deletions(-) diff --git a/validation/validation.go b/validation/validation.go index 9b4e3317..238693d2 100644 --- a/validation/validation.go +++ b/validation/validation.go @@ -84,16 +84,19 @@ func (v *Validation) Required(obj interface{}, key string) *ValidationResult { return v.apply(Required{key}, obj) } -func (v *Validation) Min(n int, min int, key string) *ValidationResult { - return v.apply(Min{min, key}, n) +// Test that the obj is greater than min if obj's type is int +func (v *Validation) Min(obj interface{}, min int, key string) *ValidationResult { + return v.apply(Min{min, key}, obj) } -func (v *Validation) Max(n int, max int, key string) *ValidationResult { - return v.apply(Max{max, key}, n) +// Test that the obj is less than max if obj's type is int +func (v *Validation) Max(obj interface{}, max int, key string) *ValidationResult { + return v.apply(Max{max, key}, obj) } -func (v *Validation) Range(n, min, max int, key string) *ValidationResult { - return v.apply(Range{Min{Min: min}, Max{Max: max}, key}, n) +// Test that the obj is between mni and max if obj's type is int +func (v *Validation) Range(obj interface{}, min, max int, key string) *ValidationResult { + return v.apply(Range{Min{Min: min}, Max{Max: max}, key}, obj) } func (v *Validation) MinSize(obj interface{}, min int, key string) *ValidationResult { @@ -120,45 +123,45 @@ func (v *Validation) AlphaNumeric(obj interface{}, key string) *ValidationResult return v.apply(AlphaNumeric{key}, obj) } -func (v *Validation) Match(str string, regex *regexp.Regexp, key string) *ValidationResult { - return v.apply(Match{regex, key}, str) +func (v *Validation) Match(obj interface{}, regex *regexp.Regexp, key string) *ValidationResult { + return v.apply(Match{regex, key}, obj) } -func (v *Validation) NoMatch(str string, regex *regexp.Regexp, key string) *ValidationResult { - return v.apply(NoMatch{Match{Regexp: regex}, key}, str) +func (v *Validation) NoMatch(obj interface{}, regex *regexp.Regexp, key string) *ValidationResult { + return v.apply(NoMatch{Match{Regexp: regex}, key}, obj) } -func (v *Validation) AlphaDash(str string, key string) *ValidationResult { - return v.apply(AlphaDash{NoMatch{Match: Match{Regexp: alphaDashPattern}}, key}, str) +func (v *Validation) AlphaDash(obj interface{}, key string) *ValidationResult { + return v.apply(AlphaDash{NoMatch{Match: Match{Regexp: alphaDashPattern}}, key}, obj) } -func (v *Validation) Email(str string, key string) *ValidationResult { - return v.apply(Email{Match{Regexp: emailPattern}, key}, str) +func (v *Validation) Email(obj interface{}, key string) *ValidationResult { + return v.apply(Email{Match{Regexp: emailPattern}, key}, obj) } -func (v *Validation) IP(str string, key string) *ValidationResult { - return v.apply(IP{Match{Regexp: ipPattern}, key}, str) +func (v *Validation) IP(obj interface{}, key string) *ValidationResult { + return v.apply(IP{Match{Regexp: ipPattern}, key}, obj) } -func (v *Validation) Base64(str string, key string) *ValidationResult { - return v.apply(Base64{Match{Regexp: base64Pattern}, key}, str) +func (v *Validation) Base64(obj interface{}, key string) *ValidationResult { + return v.apply(Base64{Match{Regexp: base64Pattern}, key}, obj) } -func (v *Validation) Mobile(str string, key string) *ValidationResult { - return v.apply(Mobile{Match{Regexp: mobilePattern}, key}, str) +func (v *Validation) Mobile(obj interface{}, key string) *ValidationResult { + return v.apply(Mobile{Match{Regexp: mobilePattern}, key}, obj) } -func (v *Validation) Tel(str string, key string) *ValidationResult { - return v.apply(Tel{Match{Regexp: telPattern}, key}, str) +func (v *Validation) Tel(obj interface{}, key string) *ValidationResult { + return v.apply(Tel{Match{Regexp: telPattern}, key}, obj) } -func (v *Validation) Phone(str string, key string) *ValidationResult { +func (v *Validation) Phone(obj interface{}, key string) *ValidationResult { return v.apply(Phone{Mobile{Match: Match{Regexp: mobilePattern}}, - Tel{Match: Match{Regexp: telPattern}}, key}, str) + Tel{Match: Match{Regexp: telPattern}}, key}, obj) } -func (v *Validation) ZipCode(str string, key string) *ValidationResult { - return v.apply(ZipCode{Match{Regexp: zipCodePattern}, key}, str) +func (v *Validation) ZipCode(obj interface{}, key string) *ValidationResult { + return v.apply(ZipCode{Match{Regexp: zipCodePattern}, key}, obj) } func (v *Validation) apply(chk Validator, obj interface{}) *ValidationResult { diff --git a/validation/validation_test.go b/validation/validation_test.go index b537b786..464d98d7 100644 --- a/validation/validation_test.go +++ b/validation/validation_test.go @@ -61,10 +61,10 @@ func TestRange(t *testing.T) { valid := Validation{} if valid.Range(-1, 0, 1, "range0_1").Ok { - t.Error("-1 is bettween 0 and 1 should be false") + t.Error("-1 is between 0 and 1 should be false") } if !valid.Range(1, 0, 1, "range0_1").Ok { - t.Error("1 is bettween 0 and 1 should be true") + t.Error("1 is between 0 and 1 should be true") } } diff --git a/validation/validators.go b/validation/validators.go index b3bbebb3..0ea6de2c 100644 --- a/validation/validators.go +++ b/validation/validators.go @@ -264,8 +264,7 @@ type Match struct { } func (m Match) IsSatisfied(obj interface{}) bool { - str := obj.(string) - return m.Regexp.MatchString(str) + return m.Regexp.MatchString(fmt.Sprintf("%v", obj)) } func (m Match) DefaultMessage() string { From 6662eef2fd02b12250b844158a670603ce80603f Mon Sep 17 00:00:00 2001 From: miraclesu Date: Sun, 28 Jul 2013 19:22:09 +0800 Subject: [PATCH 2/2] Support Match validate function for tag --- validation/README.md | 6 ++--- validation/util.go | 47 +++++++++++++++++++++++++++++------ validation/util_test.go | 17 ++++++++++--- validation/validation_test.go | 15 ++++++++--- 4 files changed, 67 insertions(+), 18 deletions(-) diff --git a/validation/README.md b/validation/README.md index c436bdd8..4bb5b416 100644 --- a/validation/README.md +++ b/validation/README.md @@ -55,9 +55,10 @@ Struct Tag Use: // validation function follow with "valid" tag // functions divide with ";" // parameters in parentheses "()" and divide with "," + // Match function's pattern string must in "//" type user struct { Id int - Name string `valid:"Required"` + Name string `valid:"Required;Match(/^(test)?\\w*@;com$/)"` Age int `valid:"Required;Range(1, 140)"` } @@ -86,8 +87,7 @@ Struct Tag Functions: Alpha Numeric AlphaNumeric - Match(regexp string) // does not support yet - NoMatch(regexp string) // does not support yet + Match(pattern string) AlphaDash Email IP diff --git a/validation/util.go b/validation/util.go index cbdb1fa3..2e34173c 100644 --- a/validation/util.go +++ b/validation/util.go @@ -26,6 +26,7 @@ var ( "apply": true, "Check": true, "Valid": true, + "NoMatch": true, } ) @@ -50,7 +51,7 @@ type Funcs map[string]reflect.Value func (f Funcs) Call(name string, params ...interface{}) (result []reflect.Value, err error) { defer func() { if r := recover(); r != nil { - err = r.(error) + err = fmt.Errorf("%v", r) } }() if _, ok := f[name]; !ok { @@ -82,10 +83,17 @@ func getValidFuncs(f reflect.StructField) (vfs []ValidFunc, err error) { if len(tag) == 0 { return } + if vfs, tag, err = getRegFuncs(tag, f.Name); err != nil { + fmt.Printf("%+v\n", err) + return + } fs := strings.Split(tag, ";") for _, vfunc := range fs { var vf ValidFunc - vf, err = parseFunc(vfunc) + if len(vfunc) == 0 { + continue + } + vf, err = parseFunc(vfunc, f.Name) if err != nil { return } @@ -94,10 +102,33 @@ func getValidFuncs(f reflect.StructField) (vfs []ValidFunc, err error) { return } -func parseFunc(vfunc string) (v ValidFunc, err error) { +// Get Match function +// May be get NoMatch function in the future +func getRegFuncs(tag, key string) (vfs []ValidFunc, str string, err error) { + tag = strings.TrimSpace(tag) + index := strings.Index(tag, "Match(/") + if index == -1 { + str = tag + return + } + end := strings.LastIndex(tag, "/)") + if end < index { + err = fmt.Errorf("invalid Match function") + return + } + reg, err := regexp.Compile(tag[index+len("Match(/") : end]) + if err != nil { + return + } + vfs = []ValidFunc{ValidFunc{"Match", []interface{}{reg, key}}} + str = strings.TrimSpace(tag[:index]) + strings.TrimSpace(tag[end+len("/)"):]) + return +} + +func parseFunc(vfunc, key string) (v ValidFunc, err error) { defer func() { if r := recover(); r != nil { - err = r.(error) + err = fmt.Errorf("%v", r) } }() @@ -114,7 +145,7 @@ func parseFunc(vfunc string) (v ValidFunc, err error) { err = fmt.Errorf("%s require %d parameters", vfunc, num) return } - v = ValidFunc{vfunc, []interface{}{vfunc}} + v = ValidFunc{vfunc, []interface{}{key}} return } @@ -136,7 +167,7 @@ func parseFunc(vfunc string) (v ValidFunc, err error) { return } - tParams, err := trim(name, params) + tParams, err := trim(name, key, params) if err != nil { return } @@ -155,7 +186,7 @@ func numIn(name string) (num int, err error) { return } -func trim(name string, s []string) (ts []interface{}, err error) { +func trim(name, key string, s []string) (ts []interface{}, err error) { ts = make([]interface{}, len(s), len(s)+1) fn, ok := funcs[name] if !ok { @@ -170,7 +201,7 @@ func trim(name string, s []string) (ts []interface{}, err error) { } ts[i] = param } - ts = append(ts, name) + ts = append(ts, key) return } diff --git a/validation/util_test.go b/validation/util_test.go index e181871f..e33025c2 100644 --- a/validation/util_test.go +++ b/validation/util_test.go @@ -6,10 +6,11 @@ import ( ) type user struct { - Id int - Tag string `valid:"Maxx(aa)"` - Name string `valid:"Required"` - Age int `valid:"Required;Range(1, 140)"` + Id int + Tag string `valid:"Maxx(aa)"` + Name string `valid:"Required;"` + Age int `valid:"Required;Range(1, 140)"` + match string `valid:"Required; Match(/^(test)?\\w*@(/test/);com$/);Max(2)"` } func TestGetValidFuncs(t *testing.T) { @@ -55,6 +56,14 @@ func TestGetValidFuncs(t *testing.T) { if vfs[1].Name != "Range" && len(vfs[1].Params) != 2 { t.Error("Range funcs should be got") } + + f, _ = tf.FieldByName("match") + if vfs, err = getValidFuncs(f); err != nil { + t.Fatal(err) + } + if len(vfs) != 3 { + t.Fatal("should get 3 ValidFunc but now is", len(vfs)) + } } func TestCall(t *testing.T) { diff --git a/validation/validation_test.go b/validation/validation_test.go index 464d98d7..2dc51c39 100644 --- a/validation/validation_test.go +++ b/validation/validation_test.go @@ -283,12 +283,12 @@ func TestZipCode(t *testing.T) { func TestValid(t *testing.T) { type user struct { Id int - Name string `valid:"Required"` + Name string `valid:"Required;Match(/^(test)?\\w*@(/test/);com$/)"` Age int `valid:"Required;Range(1, 140)"` } valid := Validation{} - u := user{Name: "test", Age: 40} + u := user{Name: "test@/test/;com", Age: 40} b, err := valid.Valid(u) if err != nil { t.Fatal(err) @@ -297,7 +297,7 @@ func TestValid(t *testing.T) { t.Error("validation should be passed") } - uptr := &user{Name: "test", Age: 180} + uptr := &user{Name: "test", Age: 40} b, err = valid.Valid(uptr) if err != nil { t.Fatal(err) @@ -305,4 +305,13 @@ func TestValid(t *testing.T) { if b { t.Error("validation should not be passed") } + + u = user{Name: "test@/test/;com", Age: 180} + b, err = valid.Valid(u) + if err != nil { + t.Fatal(err) + } + if b { + t.Error("validation should not be passed") + } }