Skip to content

Commit c06d47f

Browse files
Dean KarnDean Karn
authored andcommitted
Merge pull request #77 from bluesuncorp/v5-development
Merge new validators + godoc examples
2 parents df95f9d + 64eb07f commit c06d47f

File tree

7 files changed

+960
-186
lines changed

7 files changed

+960
-186
lines changed

baked_in.go

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,141 @@ var BakedInValidators = map[string]Func{
5050
"excludes": excludes,
5151
"excludesall": excludesAll,
5252
"excludesrune": excludesRune,
53+
"isbn": isISBN,
54+
"isbn10": isISBN10,
55+
"isbn13": isISBN13,
56+
"uuid": isUUID,
57+
"uuid3": isUUID3,
58+
"uuid4": isUUID4,
59+
"uuid5": isUUID5,
60+
"ascii": isASCII,
61+
"printascii": isPrintableASCII,
62+
"multibyte": hasMultiByteCharacter,
63+
"datauri": isDataURI,
64+
"latitude": isLatitude,
65+
"longitude": isLongitude,
66+
"ssn": isSSN,
67+
}
68+
69+
func isSSN(top interface{}, current interface{}, field interface{}, param string) bool {
70+
71+
if len(field.(string)) != 11 {
72+
return false
73+
}
74+
75+
return matchesRegex(sSNRegex, field)
76+
}
77+
78+
func isLongitude(top interface{}, current interface{}, field interface{}, param string) bool {
79+
return matchesRegex(longitudeRegex, field)
80+
}
81+
82+
func isLatitude(top interface{}, current interface{}, field interface{}, param string) bool {
83+
return matchesRegex(latitudeRegex, field)
84+
}
85+
86+
func isDataURI(top interface{}, current interface{}, field interface{}, param string) bool {
87+
88+
uri := strings.SplitN(field.(string), ",", 2)
89+
90+
if len(uri) != 2 {
91+
return false
92+
}
93+
94+
if !matchesRegex(dataURIRegex, uri[0]) {
95+
return false
96+
}
97+
98+
return isBase64(top, current, uri[1], param)
99+
}
100+
101+
func hasMultiByteCharacter(top interface{}, current interface{}, field interface{}, param string) bool {
102+
103+
if len(field.(string)) == 0 {
104+
return true
105+
}
106+
107+
return matchesRegex(multibyteRegex, field)
108+
}
109+
110+
func isPrintableASCII(top interface{}, current interface{}, field interface{}, param string) bool {
111+
return matchesRegex(printableASCIIRegex, field)
112+
}
113+
114+
func isASCII(top interface{}, current interface{}, field interface{}, param string) bool {
115+
return matchesRegex(aSCIIRegex, field)
116+
}
117+
118+
func isUUID5(top interface{}, current interface{}, field interface{}, param string) bool {
119+
return matchesRegex(uUID5Regex, field)
120+
}
121+
122+
func isUUID4(top interface{}, current interface{}, field interface{}, param string) bool {
123+
return matchesRegex(uUID4Regex, field)
124+
}
125+
126+
func isUUID3(top interface{}, current interface{}, field interface{}, param string) bool {
127+
return matchesRegex(uUID3Regex, field)
128+
}
129+
130+
func isUUID(top interface{}, current interface{}, field interface{}, param string) bool {
131+
return matchesRegex(uUIDRegex, field)
132+
}
133+
134+
func isISBN(top interface{}, current interface{}, field interface{}, param string) bool {
135+
return isISBN10(top, current, field, param) || isISBN13(top, current, field, param)
136+
}
137+
138+
func isISBN13(top interface{}, current interface{}, field interface{}, param string) bool {
139+
140+
s := strings.Replace(strings.Replace(field.(string), "-", "", 4), " ", "", 4)
141+
142+
if !matchesRegex(iSBN13Regex, s) {
143+
return false
144+
}
145+
146+
var checksum int32
147+
var i int32
148+
149+
factor := []int32{1, 3}
150+
151+
for i = 0; i < 12; i++ {
152+
checksum += factor[i%2] * int32(s[i]-'0')
153+
}
154+
155+
if (int32(s[12]-'0'))-((10-(checksum%10))%10) == 0 {
156+
return true
157+
}
158+
159+
return false
160+
}
161+
162+
func isISBN10(top interface{}, current interface{}, field interface{}, param string) bool {
163+
164+
s := strings.Replace(strings.Replace(field.(string), "-", "", 3), " ", "", 3)
165+
166+
if !matchesRegex(iSBN10Regex, s) {
167+
return false
168+
}
169+
170+
var checksum int32
171+
var i int32
172+
173+
for i = 0; i < 9; i++ {
174+
checksum += (i + 1) * int32(s[i]-'0')
175+
}
176+
177+
if s[9] == 'X' {
178+
checksum += 10 * 10
179+
} else {
180+
checksum += 10 * int32(s[9]-'0')
181+
}
182+
183+
if checksum%11 == 0 {
184+
return true
185+
}
186+
187+
return false
53188
}
54189

55190
func excludesRune(top interface{}, current interface{}, field interface{}, param string) bool {

benchmarks_test.go

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
package validator
2+
3+
import "testing"
4+
5+
func BenchmarkValidateField(b *testing.B) {
6+
for n := 0; n < b.N; n++ {
7+
validate.Field("1", "len=1")
8+
}
9+
}
10+
11+
func BenchmarkValidateStructSimple(b *testing.B) {
12+
13+
type Foo struct {
14+
StringValue string `validate:"min=5,max=10"`
15+
IntValue int `validate:"min=5,max=10"`
16+
}
17+
18+
validFoo := &Foo{StringValue: "Foobar", IntValue: 7}
19+
invalidFoo := &Foo{StringValue: "Fo", IntValue: 3}
20+
21+
for n := 0; n < b.N; n++ {
22+
validate.Struct(validFoo)
23+
validate.Struct(invalidFoo)
24+
}
25+
}
26+
27+
// func BenchmarkTemplateParallelSimple(b *testing.B) {
28+
29+
// type Foo struct {
30+
// StringValue string `validate:"min=5,max=10"`
31+
// IntValue int `validate:"min=5,max=10"`
32+
// }
33+
34+
// validFoo := &Foo{StringValue: "Foobar", IntValue: 7}
35+
// invalidFoo := &Foo{StringValue: "Fo", IntValue: 3}
36+
37+
// b.RunParallel(func(pb *testing.PB) {
38+
// for pb.Next() {
39+
// validate.Struct(validFoo)
40+
// validate.Struct(invalidFoo)
41+
// }
42+
// })
43+
// }
44+
45+
func BenchmarkValidateStructLarge(b *testing.B) {
46+
47+
tFail := &TestString{
48+
Required: "",
49+
Len: "",
50+
Min: "",
51+
Max: "12345678901",
52+
MinMax: "",
53+
Lt: "0123456789",
54+
Lte: "01234567890",
55+
Gt: "1",
56+
Gte: "1",
57+
OmitEmpty: "12345678901",
58+
Sub: &SubTest{
59+
Test: "",
60+
},
61+
Anonymous: struct {
62+
A string `validate:"required"`
63+
}{
64+
A: "",
65+
},
66+
Iface: &Impl{
67+
F: "12",
68+
},
69+
}
70+
71+
tSuccess := &TestString{
72+
Required: "Required",
73+
Len: "length==10",
74+
Min: "min=1",
75+
Max: "1234567890",
76+
MinMax: "12345",
77+
Lt: "012345678",
78+
Lte: "0123456789",
79+
Gt: "01234567890",
80+
Gte: "0123456789",
81+
OmitEmpty: "",
82+
Sub: &SubTest{
83+
Test: "1",
84+
},
85+
SubIgnore: &SubTest{
86+
Test: "",
87+
},
88+
Anonymous: struct {
89+
A string `validate:"required"`
90+
}{
91+
A: "1",
92+
},
93+
Iface: &Impl{
94+
F: "123",
95+
},
96+
}
97+
98+
for n := 0; n < b.N; n++ {
99+
validate.Struct(tSuccess)
100+
validate.Struct(tFail)
101+
}
102+
}
103+
104+
// func BenchmarkTemplateParallelLarge(b *testing.B) {
105+
106+
// tFail := &TestString{
107+
// Required: "",
108+
// Len: "",
109+
// Min: "",
110+
// Max: "12345678901",
111+
// MinMax: "",
112+
// Lt: "0123456789",
113+
// Lte: "01234567890",
114+
// Gt: "1",
115+
// Gte: "1",
116+
// OmitEmpty: "12345678901",
117+
// Sub: &SubTest{
118+
// Test: "",
119+
// },
120+
// Anonymous: struct {
121+
// A string `validate:"required"`
122+
// }{
123+
// A: "",
124+
// },
125+
// Iface: &Impl{
126+
// F: "12",
127+
// },
128+
// }
129+
130+
// tSuccess := &TestString{
131+
// Required: "Required",
132+
// Len: "length==10",
133+
// Min: "min=1",
134+
// Max: "1234567890",
135+
// MinMax: "12345",
136+
// Lt: "012345678",
137+
// Lte: "0123456789",
138+
// Gt: "01234567890",
139+
// Gte: "0123456789",
140+
// OmitEmpty: "",
141+
// Sub: &SubTest{
142+
// Test: "1",
143+
// },
144+
// SubIgnore: &SubTest{
145+
// Test: "",
146+
// },
147+
// Anonymous: struct {
148+
// A string `validate:"required"`
149+
// }{
150+
// A: "1",
151+
// },
152+
// Iface: &Impl{
153+
// F: "123",
154+
// },
155+
// }
156+
157+
// b.RunParallel(func(pb *testing.PB) {
158+
// for pb.Next() {
159+
// validate.Struct(tSuccess)
160+
// validate.Struct(tFail)
161+
// }
162+
// })
163+
// }

doc.go

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ Here is a list of the current built in validators:
168168
verify it has been assigned.
169169
170170
omitempty
171-
Allows conitional validation, for example if a field is not set with
171+
Allows conditional validation, for example if a field is not set with
172172
a value (Determined by the required validator) then other validation
173173
such as min or max won't run, but if a value is set validation will run.
174174
(Usage: omitempty)
@@ -362,6 +362,66 @@ Here is a list of the current built in validators:
362362
This validates that a string value does not contain the supplied rune value.
363363
(Usage: excludesrune=@)
364364
365+
isbn
366+
This validates that a string value contains a valid isbn10 or isbn13 value.
367+
(Usage: isbn)
368+
369+
isbn10
370+
This validates that a string value contains a valid isbn10 value.
371+
(Usage: isbn10)
372+
373+
isbn13
374+
This validates that a string value contains a valid isbn13 value.
375+
(Usage: isbn13)
376+
377+
uuid
378+
This validates that a string value contains a valid UUID.
379+
(Usage: uuid)
380+
381+
uuid3
382+
This validates that a string value contains a valid version 3 UUID.
383+
(Usage: uuid3)
384+
385+
uuid4
386+
This validates that a string value contains a valid version 4 UUID.
387+
(Usage: uuid4)
388+
389+
uuid5
390+
This validates that a string value contains a valid version 5 UUID.
391+
(Usage: uuid5)
392+
393+
ascii
394+
This validates that a string value contains only ASCII characters.
395+
NOTE: if the string is blank, this validates as true.
396+
(Usage: ascii)
397+
398+
asciiprint
399+
This validates that a string value contains only printable ASCII characters.
400+
NOTE: if the string is blank, this validates as true.
401+
(Usage: asciiprint)
402+
403+
multibyte
404+
This validates that a string value contains one or more multibyte characters.
405+
NOTE: if the string is blank, this validates as true.
406+
(Usage: multibyte)
407+
408+
datauri
409+
This validates that a string value contains a valid DataURI.
410+
NOTE: this will also validate that the data portion is valid base64
411+
(Usage: datauri)
412+
413+
latitude
414+
This validates that a string value contains a valid latitude.
415+
(Usage: latitude)
416+
417+
longitude
418+
This validates that a string value contains a valid longitude.
419+
(Usage: longitude)
420+
421+
ssn
422+
This validates that a string value contains a valid U.S. Social Security Number.
423+
(Usage: ssn)
424+
365425
Validator notes:
366426
367427
regex

0 commit comments

Comments
 (0)