Merge pull request #100 from miraclesu/valid
Valid
Showing
3 changed files
with
751 additions
and
0 deletions
validation/validation.go
0 → 100644
| 1 | package validation | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "fmt" | ||
| 5 | "regexp" | ||
| 6 | ) | ||
| 7 | |||
| 8 | type ValidationError struct { | ||
| 9 | Message, Key string | ||
| 10 | } | ||
| 11 | |||
| 12 | // Returns the Message. | ||
| 13 | func (e *ValidationError) String() string { | ||
| 14 | if e == nil { | ||
| 15 | return "" | ||
| 16 | } | ||
| 17 | return e.Message | ||
| 18 | } | ||
| 19 | |||
| 20 | // A Validation context manages data validation and error messages. | ||
| 21 | type Validation struct { | ||
| 22 | Errors []*ValidationError | ||
| 23 | } | ||
| 24 | |||
| 25 | func (v *Validation) Clear() { | ||
| 26 | v.Errors = []*ValidationError{} | ||
| 27 | } | ||
| 28 | |||
| 29 | func (v *Validation) HasErrors() bool { | ||
| 30 | return len(v.Errors) > 0 | ||
| 31 | } | ||
| 32 | |||
| 33 | // Return the errors mapped by key. | ||
| 34 | // If there are multiple validation errors associated with a single key, the | ||
| 35 | // first one "wins". (Typically the first validation will be the more basic). | ||
| 36 | func (v *Validation) ErrorMap() map[string]*ValidationError { | ||
| 37 | m := map[string]*ValidationError{} | ||
| 38 | for _, e := range v.Errors { | ||
| 39 | if _, ok := m[e.Key]; !ok { | ||
| 40 | m[e.Key] = e | ||
| 41 | } | ||
| 42 | } | ||
| 43 | return m | ||
| 44 | } | ||
| 45 | |||
| 46 | // Add an error to the validation context. | ||
| 47 | func (v *Validation) Error(message string, args ...interface{}) *ValidationResult { | ||
| 48 | result := (&ValidationResult{ | ||
| 49 | Ok: false, | ||
| 50 | Error: &ValidationError{}, | ||
| 51 | }).Message(message, args...) | ||
| 52 | v.Errors = append(v.Errors, result.Error) | ||
| 53 | return result | ||
| 54 | } | ||
| 55 | |||
| 56 | // A ValidationResult is returned from every validation method. | ||
| 57 | // It provides an indication of success, and a pointer to the Error (if any). | ||
| 58 | type ValidationResult struct { | ||
| 59 | Error *ValidationError | ||
| 60 | Ok bool | ||
| 61 | } | ||
| 62 | |||
| 63 | func (r *ValidationResult) Key(key string) *ValidationResult { | ||
| 64 | if r.Error != nil { | ||
| 65 | r.Error.Key = key | ||
| 66 | } | ||
| 67 | return r | ||
| 68 | } | ||
| 69 | |||
| 70 | func (r *ValidationResult) Message(message string, args ...interface{}) *ValidationResult { | ||
| 71 | if r.Error != nil { | ||
| 72 | if len(args) == 0 { | ||
| 73 | r.Error.Message = message | ||
| 74 | } else { | ||
| 75 | r.Error.Message = fmt.Sprintf(message, args...) | ||
| 76 | } | ||
| 77 | } | ||
| 78 | return r | ||
| 79 | } | ||
| 80 | |||
| 81 | // Test that the argument is non-nil and non-empty (if string or list) | ||
| 82 | func (v *Validation) Required(obj interface{}, key string) *ValidationResult { | ||
| 83 | return v.apply(Required{key}, obj) | ||
| 84 | } | ||
| 85 | |||
| 86 | func (v *Validation) Min(n int, min int, key string) *ValidationResult { | ||
| 87 | return v.apply(Min{min, key}, n) | ||
| 88 | } | ||
| 89 | |||
| 90 | func (v *Validation) Max(n int, max int, key string) *ValidationResult { | ||
| 91 | return v.apply(Max{max, key}, n) | ||
| 92 | } | ||
| 93 | |||
| 94 | func (v *Validation) Range(n, min, max int, key string) *ValidationResult { | ||
| 95 | return v.apply(Range{Min{Min: min}, Max{Max: max}, key}, n) | ||
| 96 | } | ||
| 97 | |||
| 98 | func (v *Validation) MinSize(obj interface{}, min int, key string) *ValidationResult { | ||
| 99 | return v.apply(MinSize{min, key}, obj) | ||
| 100 | } | ||
| 101 | |||
| 102 | func (v *Validation) MaxSize(obj interface{}, max int, key string) *ValidationResult { | ||
| 103 | return v.apply(MaxSize{max, key}, obj) | ||
| 104 | } | ||
| 105 | |||
| 106 | func (v *Validation) Length(obj interface{}, n int, key string) *ValidationResult { | ||
| 107 | return v.apply(Length{n, key}, obj) | ||
| 108 | } | ||
| 109 | |||
| 110 | func (v *Validation) Alpha(obj interface{}, key string) *ValidationResult { | ||
| 111 | return v.apply(Alpha{key}, obj) | ||
| 112 | } | ||
| 113 | |||
| 114 | func (v *Validation) Numeric(obj interface{}, key string) *ValidationResult { | ||
| 115 | return v.apply(Numeric{key}, obj) | ||
| 116 | } | ||
| 117 | |||
| 118 | func (v *Validation) AlphaNumeric(obj interface{}, key string) *ValidationResult { | ||
| 119 | return v.apply(AlphaNumeric{key}, obj) | ||
| 120 | } | ||
| 121 | |||
| 122 | func (v *Validation) Match(str string, regex *regexp.Regexp, key string) *ValidationResult { | ||
| 123 | return v.apply(Match{regex, key}, str) | ||
| 124 | } | ||
| 125 | |||
| 126 | func (v *Validation) NoMatch(str string, regex *regexp.Regexp, key string) *ValidationResult { | ||
| 127 | return v.apply(NoMatch{Match{Regexp: regex}, key}, str) | ||
| 128 | } | ||
| 129 | |||
| 130 | func (v *Validation) AlphaDash(str string, key string) *ValidationResult { | ||
| 131 | return v.apply(AlphaDash{NoMatch{Match: Match{Regexp: alphaDashPattern}}, key}, str) | ||
| 132 | } | ||
| 133 | |||
| 134 | func (v *Validation) Email(str string, key string) *ValidationResult { | ||
| 135 | return v.apply(Email{Match{Regexp: emailPattern}, key}, str) | ||
| 136 | } | ||
| 137 | |||
| 138 | func (v *Validation) IP(str string, key string) *ValidationResult { | ||
| 139 | return v.apply(IP{Match{Regexp: ipPattern}, key}, str) | ||
| 140 | } | ||
| 141 | |||
| 142 | func (v *Validation) Base64(str string, key string) *ValidationResult { | ||
| 143 | return v.apply(Base64{Match{Regexp: base64Pattern}, key}, str) | ||
| 144 | } | ||
| 145 | |||
| 146 | func (v *Validation) apply(chk Validator, obj interface{}) *ValidationResult { | ||
| 147 | if chk.IsSatisfied(obj) { | ||
| 148 | return &ValidationResult{Ok: true} | ||
| 149 | } | ||
| 150 | |||
| 151 | // Add the error to the validation context. | ||
| 152 | err := &ValidationError{ | ||
| 153 | Message: chk.DefaultMessage(), | ||
| 154 | Key: chk.GetKey(), | ||
| 155 | } | ||
| 156 | v.Errors = append(v.Errors, err) | ||
| 157 | |||
| 158 | // Also return it in the result. | ||
| 159 | return &ValidationResult{ | ||
| 160 | Ok: false, | ||
| 161 | Error: err, | ||
| 162 | } | ||
| 163 | } | ||
| 164 | |||
| 165 | // Apply a group of validators to a field, in order, and return the | ||
| 166 | // ValidationResult from the first one that fails, or the last one that | ||
| 167 | // succeeds. | ||
| 168 | func (v *Validation) Check(obj interface{}, checks ...Validator) *ValidationResult { | ||
| 169 | var result *ValidationResult | ||
| 170 | for _, check := range checks { | ||
| 171 | result = v.apply(check, obj) | ||
| 172 | if !result.Ok { | ||
| 173 | return result | ||
| 174 | } | ||
| 175 | } | ||
| 176 | return result | ||
| 177 | } |
validation/validation_test.go
0 → 100644
| 1 | package validation | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "regexp" | ||
| 5 | "testing" | ||
| 6 | "time" | ||
| 7 | ) | ||
| 8 | |||
| 9 | func TestRequired(t *testing.T) { | ||
| 10 | valid := Validation{} | ||
| 11 | |||
| 12 | if valid.Required(nil, "nil").Ok { | ||
| 13 | t.Error("nil object should be false") | ||
| 14 | } | ||
| 15 | if valid.Required("", "string").Ok { | ||
| 16 | t.Error("\"'\" string should be false") | ||
| 17 | } | ||
| 18 | if !valid.Required("astaxie", "string").Ok { | ||
| 19 | t.Error("string should be true") | ||
| 20 | } | ||
| 21 | if valid.Required(0, "zero").Ok { | ||
| 22 | t.Error("Integer should not be equal 0") | ||
| 23 | } | ||
| 24 | if !valid.Required(1, "int").Ok { | ||
| 25 | t.Error("Integer except 0 should be true") | ||
| 26 | } | ||
| 27 | if !valid.Required(time.Now(), "time").Ok { | ||
| 28 | t.Error("time should be true") | ||
| 29 | } | ||
| 30 | if valid.Required([]string{}, "emptySlice").Ok { | ||
| 31 | t.Error("empty slice should be false") | ||
| 32 | } | ||
| 33 | if !valid.Required([]interface{}{"ok"}, "slice").Ok { | ||
| 34 | t.Error("slice should be equal true") | ||
| 35 | } | ||
| 36 | } | ||
| 37 | |||
| 38 | func TestMin(t *testing.T) { | ||
| 39 | valid := Validation{} | ||
| 40 | |||
| 41 | if valid.Min(-1, 0, "min0").Ok { | ||
| 42 | t.Error("-1 is less than the minimum value of 0 should be false") | ||
| 43 | } | ||
| 44 | if !valid.Min(1, 0, "min0").Ok { | ||
| 45 | t.Error("1 is greater or equal than the minimum value of 0 should be true") | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | func TestMax(t *testing.T) { | ||
| 50 | valid := Validation{} | ||
| 51 | |||
| 52 | if valid.Max(1, 0, "max0").Ok { | ||
| 53 | t.Error("1 is greater than the minimum value of 0 should be false") | ||
| 54 | } | ||
| 55 | if !valid.Max(-1, 0, "max0").Ok { | ||
| 56 | t.Error("-1 is less or equal than the maximum value of 0 should be true") | ||
| 57 | } | ||
| 58 | } | ||
| 59 | |||
| 60 | func TestRange(t *testing.T) { | ||
| 61 | valid := Validation{} | ||
| 62 | |||
| 63 | if valid.Range(-1, 0, 1, "range0_1").Ok { | ||
| 64 | t.Error("-1 is bettween 0 and 1 should be false") | ||
| 65 | } | ||
| 66 | if !valid.Range(1, 0, 1, "range0_1").Ok { | ||
| 67 | t.Error("1 is bettween 0 and 1 should be true") | ||
| 68 | } | ||
| 69 | } | ||
| 70 | |||
| 71 | func TestMinSize(t *testing.T) { | ||
| 72 | valid := Validation{} | ||
| 73 | |||
| 74 | if valid.MinSize("", 1, "minSize1").Ok { | ||
| 75 | t.Error("the length of \"\" is less than the minimum value of 1 should be false") | ||
| 76 | } | ||
| 77 | if !valid.MinSize("ok", 1, "minSize1").Ok { | ||
| 78 | t.Error("the length of \"ok\" is greater or equal than the minimum value of 1 should be true") | ||
| 79 | } | ||
| 80 | if valid.MinSize([]string{}, 1, "minSize1").Ok { | ||
| 81 | t.Error("the length of empty slice is less than the minimum value of 1 should be false") | ||
| 82 | } | ||
| 83 | if !valid.MinSize([]interface{}{"ok"}, 1, "minSize1").Ok { | ||
| 84 | t.Error("the length of [\"ok\"] is greater or equal than the minimum value of 1 should be true") | ||
| 85 | } | ||
| 86 | } | ||
| 87 | |||
| 88 | func TestMaxSize(t *testing.T) { | ||
| 89 | valid := Validation{} | ||
| 90 | |||
| 91 | if valid.MaxSize("ok", 1, "maxSize1").Ok { | ||
| 92 | t.Error("the length of \"ok\" is greater than the maximum value of 1 should be false") | ||
| 93 | } | ||
| 94 | if !valid.MaxSize("", 1, "maxSize1").Ok { | ||
| 95 | t.Error("the length of \"\" is less or equal than the maximum value of 1 should be true") | ||
| 96 | } | ||
| 97 | if valid.MaxSize([]interface{}{"ok", false}, 1, "maxSize1").Ok { | ||
| 98 | t.Error("the length of [\"ok\", false] is greater than the maximum value of 1 should be false") | ||
| 99 | } | ||
| 100 | if !valid.MaxSize([]string{}, 1, "maxSize1").Ok { | ||
| 101 | t.Error("the length of empty slice is less or equal than the maximum value of 1 should be true") | ||
| 102 | } | ||
| 103 | } | ||
| 104 | |||
| 105 | func TestLength(t *testing.T) { | ||
| 106 | valid := Validation{} | ||
| 107 | |||
| 108 | if valid.Length("", 1, "length1").Ok { | ||
| 109 | t.Error("the length of \"\" must equal 1 should be false") | ||
| 110 | } | ||
| 111 | if !valid.Length("1", 1, "length1").Ok { | ||
| 112 | t.Error("the length of \"1\" must equal 1 should be true") | ||
| 113 | } | ||
| 114 | if valid.Length([]string{}, 1, "length1").Ok { | ||
| 115 | t.Error("the length of empty slice must equal 1 should be false") | ||
| 116 | } | ||
| 117 | if !valid.Length([]interface{}{"ok"}, 1, "length1").Ok { | ||
| 118 | t.Error("the length of [\"ok\"] must equal 1 should be true") | ||
| 119 | } | ||
| 120 | } | ||
| 121 | |||
| 122 | func TestAlpha(t *testing.T) { | ||
| 123 | valid := Validation{} | ||
| 124 | |||
| 125 | if valid.Alpha("a,1-@ $", "alpha").Ok { | ||
| 126 | t.Error("\"a,1-@ $\" are valid alpha characters should be false") | ||
| 127 | } | ||
| 128 | if !valid.Alpha("abCD", "alpha").Ok { | ||
| 129 | t.Error("\"abCD\" are valid alpha characters should be true") | ||
| 130 | } | ||
| 131 | } | ||
| 132 | |||
| 133 | func TestNumeric(t *testing.T) { | ||
| 134 | valid := Validation{} | ||
| 135 | |||
| 136 | if valid.Numeric("a,1-@ $", "numeric").Ok { | ||
| 137 | t.Error("\"a,1-@ $\" are valid numeric characters should be false") | ||
| 138 | } | ||
| 139 | if !valid.Numeric("1234", "numeric").Ok { | ||
| 140 | t.Error("\"1234\" are valid numeric characters should be true") | ||
| 141 | } | ||
| 142 | } | ||
| 143 | |||
| 144 | func TestAlphaNumeric(t *testing.T) { | ||
| 145 | valid := Validation{} | ||
| 146 | |||
| 147 | if valid.AlphaNumeric("a,1-@ $", "alphaNumeric").Ok { | ||
| 148 | t.Error("\"a,1-@ $\" are valid alpha or numeric characters should be false") | ||
| 149 | } | ||
| 150 | if !valid.AlphaNumeric("1234aB", "alphaNumeric").Ok { | ||
| 151 | t.Error("\"1234aB\" are valid alpha or numeric characters should be true") | ||
| 152 | } | ||
| 153 | } | ||
| 154 | |||
| 155 | func TestMatch(t *testing.T) { | ||
| 156 | valid := Validation{} | ||
| 157 | |||
| 158 | if valid.Match("suchuangji@gmail", regexp.MustCompile("^\\w+@\\w+\\.\\w+$"), "match").Ok { | ||
| 159 | t.Error("\"suchuangji@gmail\" match \"^\\w+@\\w+\\.\\w+$\" should be false") | ||
| 160 | } | ||
| 161 | if !valid.Match("suchuangji@gmail.com", regexp.MustCompile("^\\w+@\\w+\\.\\w+$"), "match").Ok { | ||
| 162 | t.Error("\"suchuangji@gmail\" match \"^\\w+@\\w+\\.\\w+$\" should be true") | ||
| 163 | } | ||
| 164 | } | ||
| 165 | |||
| 166 | func TestNoMatch(t *testing.T) { | ||
| 167 | valid := Validation{} | ||
| 168 | |||
| 169 | if valid.NoMatch("123@gmail", regexp.MustCompile("[^\\w\\d]"), "nomatch").Ok { | ||
| 170 | t.Error("\"123@gmail\" not match \"[^\\w\\d]\" should be false") | ||
| 171 | } | ||
| 172 | if !valid.NoMatch("123gmail", regexp.MustCompile("[^\\w\\d]"), "match").Ok { | ||
| 173 | t.Error("\"123@gmail\" not match \"[^\\w\\d@]\" should be true") | ||
| 174 | } | ||
| 175 | } | ||
| 176 | |||
| 177 | func TestAlphaDash(t *testing.T) { | ||
| 178 | valid := Validation{} | ||
| 179 | |||
| 180 | if valid.AlphaDash("a,1-@ $", "alphaDash").Ok { | ||
| 181 | t.Error("\"a,1-@ $\" are valid alpha or numeric or dash(-_) characters should be false") | ||
| 182 | } | ||
| 183 | if !valid.AlphaDash("1234aB-_", "alphaDash").Ok { | ||
| 184 | t.Error("\"1234aB\" are valid alpha or numeric or dash(-_) characters should be true") | ||
| 185 | } | ||
| 186 | } | ||
| 187 | |||
| 188 | func TestEmail(t *testing.T) { | ||
| 189 | valid := Validation{} | ||
| 190 | |||
| 191 | if valid.Email("not@a email", "email").Ok { | ||
| 192 | t.Error("\"not@a email\" is a valid email address should be false") | ||
| 193 | } | ||
| 194 | if !valid.Email("suchuangji@gmail.com", "email").Ok { | ||
| 195 | t.Error("\"suchuangji@gmail.com\" is a valid email address should be true") | ||
| 196 | } | ||
| 197 | } | ||
| 198 | |||
| 199 | func TestIP(t *testing.T) { | ||
| 200 | valid := Validation{} | ||
| 201 | |||
| 202 | if valid.IP("11.255.255.256", "IP").Ok { | ||
| 203 | t.Error("\"11.255.255.256\" is a valid ip address should be false") | ||
| 204 | } | ||
| 205 | if !valid.IP("01.11.11.11", "IP").Ok { | ||
| 206 | t.Error("\"suchuangji@gmail.com\" is a valid ip address should be true") | ||
| 207 | } | ||
| 208 | } | ||
| 209 | |||
| 210 | func TestBase64(t *testing.T) { | ||
| 211 | valid := Validation{} | ||
| 212 | |||
| 213 | if valid.Base64("suchuangji@gmail.com", "base64").Ok { | ||
| 214 | t.Error("\"suchuangji@gmail.com\" are a valid base64 characters should be false") | ||
| 215 | } | ||
| 216 | if !valid.Base64("c3VjaHVhbmdqaUBnbWFpbC5jb20=", "base64").Ok { | ||
| 217 | t.Error("\"c3VjaHVhbmdqaUBnbWFpbC5jb20=\" are a valid base64 characters should be true") | ||
| 218 | } | ||
| 219 | } |
validation/validators.go
0 → 100644
| 1 | package validation | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "fmt" | ||
| 5 | "reflect" | ||
| 6 | "regexp" | ||
| 7 | "time" | ||
| 8 | ) | ||
| 9 | |||
| 10 | type Validator interface { | ||
| 11 | IsSatisfied(interface{}) bool | ||
| 12 | DefaultMessage() string | ||
| 13 | GetKey() string | ||
| 14 | } | ||
| 15 | |||
| 16 | type Required struct { | ||
| 17 | Key string | ||
| 18 | } | ||
| 19 | |||
| 20 | func (r Required) IsSatisfied(obj interface{}) bool { | ||
| 21 | if obj == nil { | ||
| 22 | return false | ||
| 23 | } | ||
| 24 | |||
| 25 | if str, ok := obj.(string); ok { | ||
| 26 | return len(str) > 0 | ||
| 27 | } | ||
| 28 | if b, ok := obj.(bool); ok { | ||
| 29 | return b | ||
| 30 | } | ||
| 31 | if i, ok := obj.(int); ok { | ||
| 32 | return i != 0 | ||
| 33 | } | ||
| 34 | if t, ok := obj.(time.Time); ok { | ||
| 35 | return !t.IsZero() | ||
| 36 | } | ||
| 37 | v := reflect.ValueOf(obj) | ||
| 38 | if v.Kind() == reflect.Slice { | ||
| 39 | return v.Len() > 0 | ||
| 40 | } | ||
| 41 | return true | ||
| 42 | } | ||
| 43 | |||
| 44 | func (r Required) DefaultMessage() string { | ||
| 45 | return "Required" | ||
| 46 | } | ||
| 47 | |||
| 48 | func (r Required) GetKey() string { | ||
| 49 | return r.Key | ||
| 50 | } | ||
| 51 | |||
| 52 | type Min struct { | ||
| 53 | Min int | ||
| 54 | Key string | ||
| 55 | } | ||
| 56 | |||
| 57 | func (m Min) IsSatisfied(obj interface{}) bool { | ||
| 58 | num, ok := obj.(int) | ||
| 59 | if ok { | ||
| 60 | return num >= m.Min | ||
| 61 | } | ||
| 62 | return false | ||
| 63 | } | ||
| 64 | |||
| 65 | func (m Min) DefaultMessage() string { | ||
| 66 | return fmt.Sprintln("Minimum is", m.Min) | ||
| 67 | } | ||
| 68 | |||
| 69 | func (m Min) GetKey() string { | ||
| 70 | return m.Key | ||
| 71 | } | ||
| 72 | |||
| 73 | type Max struct { | ||
| 74 | Max int | ||
| 75 | Key string | ||
| 76 | } | ||
| 77 | |||
| 78 | func (m Max) IsSatisfied(obj interface{}) bool { | ||
| 79 | num, ok := obj.(int) | ||
| 80 | if ok { | ||
| 81 | return num <= m.Max | ||
| 82 | } | ||
| 83 | return false | ||
| 84 | } | ||
| 85 | |||
| 86 | func (m Max) DefaultMessage() string { | ||
| 87 | return fmt.Sprintln("Maximum is", m.Max) | ||
| 88 | } | ||
| 89 | |||
| 90 | func (m Max) GetKey() string { | ||
| 91 | return m.Key | ||
| 92 | } | ||
| 93 | |||
| 94 | // Requires an integer to be within Min, Max inclusive. | ||
| 95 | type Range struct { | ||
| 96 | Min | ||
| 97 | Max | ||
| 98 | Key string | ||
| 99 | } | ||
| 100 | |||
| 101 | func (r Range) IsSatisfied(obj interface{}) bool { | ||
| 102 | return r.Min.IsSatisfied(obj) && r.Max.IsSatisfied(obj) | ||
| 103 | } | ||
| 104 | |||
| 105 | func (r Range) DefaultMessage() string { | ||
| 106 | return fmt.Sprintln("Range is", r.Min.Min, "to", r.Max.Max) | ||
| 107 | } | ||
| 108 | |||
| 109 | func (r Range) GetKey() string { | ||
| 110 | return r.Key | ||
| 111 | } | ||
| 112 | |||
| 113 | // Requires an array or string to be at least a given length. | ||
| 114 | type MinSize struct { | ||
| 115 | Min int | ||
| 116 | Key string | ||
| 117 | } | ||
| 118 | |||
| 119 | func (m MinSize) IsSatisfied(obj interface{}) bool { | ||
| 120 | if str, ok := obj.(string); ok { | ||
| 121 | return len(str) >= m.Min | ||
| 122 | } | ||
| 123 | v := reflect.ValueOf(obj) | ||
| 124 | if v.Kind() == reflect.Slice { | ||
| 125 | return v.Len() >= m.Min | ||
| 126 | } | ||
| 127 | return false | ||
| 128 | } | ||
| 129 | |||
| 130 | func (m MinSize) DefaultMessage() string { | ||
| 131 | return fmt.Sprintln("Minimum size is", m.Min) | ||
| 132 | } | ||
| 133 | |||
| 134 | func (m MinSize) GetKey() string { | ||
| 135 | return m.Key | ||
| 136 | } | ||
| 137 | |||
| 138 | // Requires an array or string to be at most a given length. | ||
| 139 | type MaxSize struct { | ||
| 140 | Max int | ||
| 141 | Key string | ||
| 142 | } | ||
| 143 | |||
| 144 | func (m MaxSize) IsSatisfied(obj interface{}) bool { | ||
| 145 | if str, ok := obj.(string); ok { | ||
| 146 | return len(str) <= m.Max | ||
| 147 | } | ||
| 148 | v := reflect.ValueOf(obj) | ||
| 149 | if v.Kind() == reflect.Slice { | ||
| 150 | return v.Len() <= m.Max | ||
| 151 | } | ||
| 152 | return false | ||
| 153 | } | ||
| 154 | |||
| 155 | func (m MaxSize) DefaultMessage() string { | ||
| 156 | return fmt.Sprintln("Maximum size is", m.Max) | ||
| 157 | } | ||
| 158 | |||
| 159 | func (m MaxSize) GetKey() string { | ||
| 160 | return m.Key | ||
| 161 | } | ||
| 162 | |||
| 163 | // Requires an array or string to be exactly a given length. | ||
| 164 | type Length struct { | ||
| 165 | N int | ||
| 166 | Key string | ||
| 167 | } | ||
| 168 | |||
| 169 | func (l Length) IsSatisfied(obj interface{}) bool { | ||
| 170 | if str, ok := obj.(string); ok { | ||
| 171 | return len(str) == l.N | ||
| 172 | } | ||
| 173 | v := reflect.ValueOf(obj) | ||
| 174 | if v.Kind() == reflect.Slice { | ||
| 175 | return v.Len() == l.N | ||
| 176 | } | ||
| 177 | return false | ||
| 178 | } | ||
| 179 | |||
| 180 | func (l Length) DefaultMessage() string { | ||
| 181 | return fmt.Sprintln("Required length is", l.N) | ||
| 182 | } | ||
| 183 | |||
| 184 | func (l Length) GetKey() string { | ||
| 185 | return l.Key | ||
| 186 | } | ||
| 187 | |||
| 188 | type Alpha struct { | ||
| 189 | Key string | ||
| 190 | } | ||
| 191 | |||
| 192 | func (a Alpha) IsSatisfied(obj interface{}) bool { | ||
| 193 | if str, ok := obj.(string); ok { | ||
| 194 | for _, v := range str { | ||
| 195 | if ('Z' < v || v < 'A') && ('z' < v || v < 'a') { | ||
| 196 | return false | ||
| 197 | } | ||
| 198 | } | ||
| 199 | return true | ||
| 200 | } | ||
| 201 | return false | ||
| 202 | } | ||
| 203 | |||
| 204 | func (a Alpha) DefaultMessage() string { | ||
| 205 | return fmt.Sprintln("Must be valid alpha characters") | ||
| 206 | } | ||
| 207 | |||
| 208 | func (a Alpha) GetKey() string { | ||
| 209 | return a.Key | ||
| 210 | } | ||
| 211 | |||
| 212 | type Numeric struct { | ||
| 213 | Key string | ||
| 214 | } | ||
| 215 | |||
| 216 | func (n Numeric) IsSatisfied(obj interface{}) bool { | ||
| 217 | if str, ok := obj.(string); ok { | ||
| 218 | for _, v := range str { | ||
| 219 | if '9' < v || v < '0' { | ||
| 220 | return false | ||
| 221 | } | ||
| 222 | } | ||
| 223 | return true | ||
| 224 | } | ||
| 225 | return false | ||
| 226 | } | ||
| 227 | |||
| 228 | func (n Numeric) DefaultMessage() string { | ||
| 229 | return fmt.Sprintln("Must be valid numeric characters") | ||
| 230 | } | ||
| 231 | |||
| 232 | func (n Numeric) GetKey() string { | ||
| 233 | return n.Key | ||
| 234 | } | ||
| 235 | |||
| 236 | type AlphaNumeric struct { | ||
| 237 | Key string | ||
| 238 | } | ||
| 239 | |||
| 240 | func (a AlphaNumeric) IsSatisfied(obj interface{}) bool { | ||
| 241 | if str, ok := obj.(string); ok { | ||
| 242 | for _, v := range str { | ||
| 243 | if ('Z' < v || v < 'A') && ('z' < v || v < 'a') && ('9' < v || v < '0') { | ||
| 244 | return false | ||
| 245 | } | ||
| 246 | } | ||
| 247 | return true | ||
| 248 | } | ||
| 249 | return false | ||
| 250 | } | ||
| 251 | |||
| 252 | func (a AlphaNumeric) DefaultMessage() string { | ||
| 253 | return fmt.Sprintln("Must be valid alpha or numeric characters") | ||
| 254 | } | ||
| 255 | |||
| 256 | func (a AlphaNumeric) GetKey() string { | ||
| 257 | return a.Key | ||
| 258 | } | ||
| 259 | |||
| 260 | // Requires a string to match a given regex. | ||
| 261 | type Match struct { | ||
| 262 | Regexp *regexp.Regexp | ||
| 263 | Key string | ||
| 264 | } | ||
| 265 | |||
| 266 | func (m Match) IsSatisfied(obj interface{}) bool { | ||
| 267 | str := obj.(string) | ||
| 268 | return m.Regexp.MatchString(str) | ||
| 269 | } | ||
| 270 | |||
| 271 | func (m Match) DefaultMessage() string { | ||
| 272 | return fmt.Sprintln("Must match", m.Regexp) | ||
| 273 | } | ||
| 274 | |||
| 275 | func (m Match) GetKey() string { | ||
| 276 | return m.Key | ||
| 277 | } | ||
| 278 | |||
| 279 | // Requires a string to not match a given regex. | ||
| 280 | type NoMatch struct { | ||
| 281 | Match | ||
| 282 | Key string | ||
| 283 | } | ||
| 284 | |||
| 285 | func (n NoMatch) IsSatisfied(obj interface{}) bool { | ||
| 286 | return !n.Match.IsSatisfied(obj) | ||
| 287 | } | ||
| 288 | |||
| 289 | func (n NoMatch) DefaultMessage() string { | ||
| 290 | return fmt.Sprintln("Must not match", n.Regexp) | ||
| 291 | } | ||
| 292 | |||
| 293 | func (n NoMatch) GetKey() string { | ||
| 294 | return n.Key | ||
| 295 | } | ||
| 296 | |||
| 297 | var alphaDashPattern = regexp.MustCompile("[^\\d\\w-_]") | ||
| 298 | |||
| 299 | type AlphaDash struct { | ||
| 300 | NoMatch | ||
| 301 | Key string | ||
| 302 | } | ||
| 303 | |||
| 304 | func (a AlphaDash) DefaultMessage() string { | ||
| 305 | return fmt.Sprintln("Must be valid alpha or numeric or dash(-_) characters") | ||
| 306 | } | ||
| 307 | |||
| 308 | func (a AlphaDash) GetKey() string { | ||
| 309 | return a.Key | ||
| 310 | } | ||
| 311 | |||
| 312 | var emailPattern = regexp.MustCompile("[\\w!#$%&'*+/=?^_`{|}~-]+(?:\\.[\\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\\w](?:[\\w-]*[\\w])?\\.)+[a-zA-Z0-9](?:[\\w-]*[\\w])?") | ||
| 313 | |||
| 314 | type Email struct { | ||
| 315 | Match | ||
| 316 | Key string | ||
| 317 | } | ||
| 318 | |||
| 319 | func (e Email) DefaultMessage() string { | ||
| 320 | return fmt.Sprintln("Must be a valid email address") | ||
| 321 | } | ||
| 322 | |||
| 323 | func (e Email) GetKey() string { | ||
| 324 | return e.Key | ||
| 325 | } | ||
| 326 | |||
| 327 | var ipPattern = regexp.MustCompile("^((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)$") | ||
| 328 | |||
| 329 | type IP struct { | ||
| 330 | Match | ||
| 331 | Key string | ||
| 332 | } | ||
| 333 | |||
| 334 | func (i IP) DefaultMessage() string { | ||
| 335 | return fmt.Sprintln("Must be a valid ip address") | ||
| 336 | } | ||
| 337 | |||
| 338 | func (i IP) GetKey() string { | ||
| 339 | return i.Key | ||
| 340 | } | ||
| 341 | |||
| 342 | var base64Pattern = regexp.MustCompile("^(?:[A-Za-z0-99+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$") | ||
| 343 | |||
| 344 | type Base64 struct { | ||
| 345 | Match | ||
| 346 | Key string | ||
| 347 | } | ||
| 348 | |||
| 349 | func (b Base64) DefaultMessage() string { | ||
| 350 | return fmt.Sprintln("Must be valid base64 characters") | ||
| 351 | } | ||
| 352 | |||
| 353 | func (b Base64) GetKey() string { | ||
| 354 | return b.Key | ||
| 355 | } |
-
Please register or sign in to post a comment