Skip to content

Commit 73747bd

Browse files
Dean KarnDean Karn
Dean Karn
authored and
Dean Karn
committed
Merge pull request #37 from bluesuncorp/v5-development
V5 development
2 parents 4e94615 + 1a0a2f5 commit 73747bd

File tree

4 files changed

+244
-1
lines changed

4 files changed

+244
-1
lines changed

baked_in.go

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@ var BakedInValidators = map[string]Func{
1616
"len": hasLengthOf,
1717
"min": hasMinOf,
1818
"max": hasMaxOf,
19+
"eq": isEq,
1920
"lt": isLt,
2021
"lte": isLte,
2122
"gt": isGt,
2223
"gte": isGte,
24+
"eqfield": isEqField,
2325
"gtefield": isGteField,
2426
"gtfield": isGtField,
2527
"ltefield": isLteField,
@@ -40,6 +42,119 @@ var BakedInValidators = map[string]Func{
4042
"base64": isBase64,
4143
}
4244

45+
func isEqField(top interface{}, current interface{}, field interface{}, param string) bool {
46+
47+
if current == nil {
48+
panic("struct not passed for cross validation")
49+
}
50+
51+
currentVal := reflect.ValueOf(current)
52+
53+
if currentVal.Kind() == reflect.Ptr && !currentVal.IsNil() {
54+
currentVal = reflect.ValueOf(currentVal.Elem().Interface())
55+
}
56+
57+
var currentFielVal reflect.Value
58+
59+
switch currentVal.Kind() {
60+
61+
case reflect.Struct:
62+
63+
if currentVal.Type() == reflect.TypeOf(time.Time{}) {
64+
currentFielVal = currentVal
65+
break
66+
}
67+
68+
f := currentVal.FieldByName(param)
69+
70+
if f.Kind() == reflect.Invalid {
71+
panic(fmt.Sprintf("Field \"%s\" not found in struct", param))
72+
}
73+
74+
currentFielVal = f
75+
76+
default:
77+
78+
currentFielVal = currentVal
79+
}
80+
81+
if currentFielVal.Kind() == reflect.Ptr && !currentFielVal.IsNil() {
82+
83+
currentFielVal = reflect.ValueOf(currentFielVal.Elem().Interface())
84+
}
85+
86+
fv := reflect.ValueOf(field)
87+
88+
switch fv.Kind() {
89+
90+
case reflect.String:
91+
return fv.String() == currentFielVal.String()
92+
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
93+
94+
return fv.Int() == currentFielVal.Int()
95+
96+
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
97+
98+
return fv.Uint() == currentFielVal.Uint()
99+
100+
case reflect.Float32, reflect.Float64:
101+
102+
return fv.Float() == currentFielVal.Float()
103+
case reflect.Slice, reflect.Map, reflect.Array:
104+
105+
return int64(fv.Len()) == int64(currentFielVal.Len())
106+
case reflect.Struct:
107+
108+
if fv.Type() == reflect.TypeOf(time.Time{}) {
109+
110+
if currentFielVal.Type() != reflect.TypeOf(time.Time{}) {
111+
panic("Bad Top Level field type")
112+
}
113+
114+
t := currentFielVal.Interface().(time.Time)
115+
fieldTime := field.(time.Time)
116+
117+
return fieldTime.Equal(t)
118+
}
119+
}
120+
121+
panic(fmt.Sprintf("Bad field type %T", field))
122+
}
123+
124+
func isEq(top interface{}, current interface{}, field interface{}, param string) bool {
125+
126+
st := reflect.ValueOf(field)
127+
128+
switch st.Kind() {
129+
130+
case reflect.String:
131+
132+
return st.String() == param
133+
134+
case reflect.Slice, reflect.Map, reflect.Array:
135+
p := asInt(param)
136+
137+
return int64(st.Len()) == p
138+
139+
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
140+
p := asInt(param)
141+
142+
return st.Int() == p
143+
144+
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
145+
p := asUint(param)
146+
147+
return st.Uint() == p
148+
149+
case reflect.Float32, reflect.Float64:
150+
p := asFloat(param)
151+
152+
return st.Float() == p
153+
}
154+
155+
panic(fmt.Sprintf("Bad field type %T", field))
156+
}
157+
43158
func isBase64(top interface{}, current interface{}, field interface{}, param string) bool {
44159
return matchesRegex(base64Regex, field)
45160
}

doc.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,11 @@ Here is a list of the current built in validators:
192192
the string length is at least that number of characters. For slices,
193193
arrays, and maps, validates the number of items. (Usage: min=10)
194194
195+
eq
196+
For strings & numbers, eq will ensure that the value is
197+
equal to the parameter given. For slices, arrays, and maps,
198+
validates the number of items. (Usage: eq=10)
199+
195200
gt
196201
For numbers, this will ensure that the value is greater than the
197202
parameter given. For strings, it checks that the string length
@@ -221,6 +226,13 @@ Here is a list of the current built in validators:
221226
For time.Time ensures the time value is less than or equal to time.Now.UTC()
222227
(Usage: lte)
223228
229+
eqfield
230+
This will validate the field value against another fields value either within
231+
a struct or passed in field.
232+
usage examples are for validation of a password and confirm password:
233+
Validation on Password field using validate.Struct Usage(eqfield=ConfirmPassword)
234+
Validating by field validate.FieldWithValue(password, confirmpassword, "eqfield")
235+
224236
gtfield
225237
Only valid for Numbers and time.Time types, this will validate the field value
226238
against another fields value either within a struct or passed in field.

validator.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ func (v *Validate) structRecursive(top interface{}, current interface{}, s inter
200200
}
201201

202202
// if no validation and not a struct (which may containt fields for validation)
203-
if tag == "" && valueField.Kind() != reflect.Struct && valueField.Kind() != reflect.Interface {
203+
if tag == "" && ((valueField.Kind() != reflect.Struct && valueField.Kind() != reflect.Interface) || valueField.Type() == reflect.TypeOf(time.Time{})) {
204204
continue
205205
}
206206

validator_test.go

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,122 @@ func isEqualFunc(val interface{}, current interface{}, field interface{}, param
142142
return current.(string) == field.(string)
143143
}
144144

145+
func (ms *MySuite) TestIsEqFieldValidation(c *C) {
146+
147+
var j uint64
148+
var k float64
149+
s := "abcd"
150+
i := 1
151+
j = 1
152+
k = 1.543
153+
arr := []string{"test"}
154+
now := time.Now().UTC()
155+
156+
var j2 uint64
157+
var k2 float64
158+
s2 := "abcd"
159+
i2 := 1
160+
j2 = 1
161+
k2 = 1.543
162+
arr2 := []string{"test"}
163+
arr3 := []string{"test", "test2"}
164+
now2 := now
165+
166+
err := validate.FieldWithValue(s, s2, "eqfield")
167+
c.Assert(err, IsNil)
168+
169+
err = validate.FieldWithValue(i2, i, "eqfield")
170+
c.Assert(err, IsNil)
171+
172+
err = validate.FieldWithValue(j2, j, "eqfield")
173+
c.Assert(err, IsNil)
174+
175+
err = validate.FieldWithValue(k2, k, "eqfield")
176+
c.Assert(err, IsNil)
177+
178+
err = validate.FieldWithValue(arr2, arr, "eqfield")
179+
c.Assert(err, IsNil)
180+
181+
err = validate.FieldWithValue(now2, now, "eqfield")
182+
c.Assert(err, IsNil)
183+
184+
err = validate.FieldWithValue(arr3, arr, "eqfield")
185+
c.Assert(err, NotNil)
186+
187+
type Test struct {
188+
Start *time.Time `validate:"eqfield=End"`
189+
End *time.Time
190+
}
191+
192+
sv := &Test{
193+
Start: &now,
194+
End: &now,
195+
}
196+
197+
errs := validate.Struct(sv)
198+
c.Assert(errs, IsNil)
199+
200+
now3 := time.Now().UTC()
201+
202+
sv = &Test{
203+
Start: &now,
204+
End: &now3,
205+
}
206+
207+
errs = validate.Struct(sv)
208+
c.Assert(errs, NotNil)
209+
210+
channel := make(chan string)
211+
212+
c.Assert(func() { validate.FieldWithValue(nil, 1, "eqfield") }, PanicMatches, "struct not passed for cross validation")
213+
c.Assert(func() { validate.FieldWithValue(5, channel, "eqfield") }, PanicMatches, "Bad field type chan string")
214+
c.Assert(func() { validate.FieldWithValue(5, now, "eqfield") }, PanicMatches, "Bad Top Level field type")
215+
216+
type Test2 struct {
217+
Start *time.Time `validate:"eqfield=NonExistantField"`
218+
End *time.Time
219+
}
220+
221+
sv2 := &Test2{
222+
Start: &now,
223+
End: &now,
224+
}
225+
226+
c.Assert(func() { validate.Struct(sv2) }, PanicMatches, "Field \"NonExistantField\" not found in struct")
227+
}
228+
229+
func (ms *MySuite) TestIsEqValidation(c *C) {
230+
231+
var j uint64
232+
var k float64
233+
s := "abcd"
234+
i := 1
235+
j = 1
236+
k = 1.543
237+
arr := []string{"test"}
238+
now := time.Now().UTC()
239+
240+
err := validate.Field(s, "eq=abcd")
241+
c.Assert(err, IsNil)
242+
243+
err = validate.Field(i, "eq=1")
244+
c.Assert(err, IsNil)
245+
246+
err = validate.Field(j, "eq=1")
247+
c.Assert(err, IsNil)
248+
249+
err = validate.Field(k, "eq=1.543")
250+
c.Assert(err, IsNil)
251+
252+
err = validate.Field(arr, "eq=1")
253+
c.Assert(err, IsNil)
254+
255+
err = validate.Field(arr, "eq=2")
256+
c.Assert(err, NotNil)
257+
258+
c.Assert(func() { validate.Field(now, "eq=now") }, PanicMatches, "Bad field type time.Time")
259+
}
260+
145261
func (ms *MySuite) TestBase64Validation(c *C) {
146262

147263
s := "dW5pY29ybg=="

0 commit comments

Comments
 (0)