Codebase list golang-github-go-playground-validator-v10 / 64eb07f
Merge pull request #76 from joeybloggs/v5-development Add More Validators + Add godoc examples Dean Karn 8 years ago
7 changed file(s) with 960 addition(s) and 186 deletion(s). Raw diff Collapse all Expand all
4949 "excludes": excludes,
5050 "excludesall": excludesAll,
5151 "excludesrune": excludesRune,
52 "isbn": isISBN,
53 "isbn10": isISBN10,
54 "isbn13": isISBN13,
55 "uuid": isUUID,
56 "uuid3": isUUID3,
57 "uuid4": isUUID4,
58 "uuid5": isUUID5,
59 "ascii": isASCII,
60 "printascii": isPrintableASCII,
61 "multibyte": hasMultiByteCharacter,
62 "datauri": isDataURI,
63 "latitude": isLatitude,
64 "longitude": isLongitude,
65 "ssn": isSSN,
66 }
67
68 func isSSN(top interface{}, current interface{}, field interface{}, param string) bool {
69
70 if len(field.(string)) != 11 {
71 return false
72 }
73
74 return matchesRegex(sSNRegex, field)
75 }
76
77 func isLongitude(top interface{}, current interface{}, field interface{}, param string) bool {
78 return matchesRegex(longitudeRegex, field)
79 }
80
81 func isLatitude(top interface{}, current interface{}, field interface{}, param string) bool {
82 return matchesRegex(latitudeRegex, field)
83 }
84
85 func isDataURI(top interface{}, current interface{}, field interface{}, param string) bool {
86
87 uri := strings.SplitN(field.(string), ",", 2)
88
89 if len(uri) != 2 {
90 return false
91 }
92
93 if !matchesRegex(dataURIRegex, uri[0]) {
94 return false
95 }
96
97 return isBase64(top, current, uri[1], param)
98 }
99
100 func hasMultiByteCharacter(top interface{}, current interface{}, field interface{}, param string) bool {
101
102 if len(field.(string)) == 0 {
103 return true
104 }
105
106 return matchesRegex(multibyteRegex, field)
107 }
108
109 func isPrintableASCII(top interface{}, current interface{}, field interface{}, param string) bool {
110 return matchesRegex(printableASCIIRegex, field)
111 }
112
113 func isASCII(top interface{}, current interface{}, field interface{}, param string) bool {
114 return matchesRegex(aSCIIRegex, field)
115 }
116
117 func isUUID5(top interface{}, current interface{}, field interface{}, param string) bool {
118 return matchesRegex(uUID5Regex, field)
119 }
120
121 func isUUID4(top interface{}, current interface{}, field interface{}, param string) bool {
122 return matchesRegex(uUID4Regex, field)
123 }
124
125 func isUUID3(top interface{}, current interface{}, field interface{}, param string) bool {
126 return matchesRegex(uUID3Regex, field)
127 }
128
129 func isUUID(top interface{}, current interface{}, field interface{}, param string) bool {
130 return matchesRegex(uUIDRegex, field)
131 }
132
133 func isISBN(top interface{}, current interface{}, field interface{}, param string) bool {
134 return isISBN10(top, current, field, param) || isISBN13(top, current, field, param)
135 }
136
137 func isISBN13(top interface{}, current interface{}, field interface{}, param string) bool {
138
139 s := strings.Replace(strings.Replace(field.(string), "-", "", 4), " ", "", 4)
140
141 if !matchesRegex(iSBN13Regex, s) {
142 return false
143 }
144
145 var checksum int32
146 var i int32
147
148 factor := []int32{1, 3}
149
150 for i = 0; i < 12; i++ {
151 checksum += factor[i%2] * int32(s[i]-'0')
152 }
153
154 if (int32(s[12]-'0'))-((10-(checksum%10))%10) == 0 {
155 return true
156 }
157
158 return false
159 }
160
161 func isISBN10(top interface{}, current interface{}, field interface{}, param string) bool {
162
163 s := strings.Replace(strings.Replace(field.(string), "-", "", 3), " ", "", 3)
164
165 if !matchesRegex(iSBN10Regex, s) {
166 return false
167 }
168
169 var checksum int32
170 var i int32
171
172 for i = 0; i < 9; i++ {
173 checksum += (i + 1) * int32(s[i]-'0')
174 }
175
176 if s[9] == 'X' {
177 checksum += 10 * 10
178 } else {
179 checksum += 10 * int32(s[9]-'0')
180 }
181
182 if checksum%11 == 0 {
183 return true
184 }
185
186 return false
52187 }
53188
54189 func excludesRune(top interface{}, current interface{}, field interface{}, param string) bool {
0 package validator
1
2 import "testing"
3
4 func BenchmarkValidateField(b *testing.B) {
5 for n := 0; n < b.N; n++ {
6 validate.Field("1", "len=1")
7 }
8 }
9
10 func BenchmarkValidateStructSimple(b *testing.B) {
11
12 type Foo struct {
13 StringValue string `validate:"min=5,max=10"`
14 IntValue int `validate:"min=5,max=10"`
15 }
16
17 validFoo := &Foo{StringValue: "Foobar", IntValue: 7}
18 invalidFoo := &Foo{StringValue: "Fo", IntValue: 3}
19
20 for n := 0; n < b.N; n++ {
21 validate.Struct(validFoo)
22 validate.Struct(invalidFoo)
23 }
24 }
25
26 // func BenchmarkTemplateParallelSimple(b *testing.B) {
27
28 // type Foo struct {
29 // StringValue string `validate:"min=5,max=10"`
30 // IntValue int `validate:"min=5,max=10"`
31 // }
32
33 // validFoo := &Foo{StringValue: "Foobar", IntValue: 7}
34 // invalidFoo := &Foo{StringValue: "Fo", IntValue: 3}
35
36 // b.RunParallel(func(pb *testing.PB) {
37 // for pb.Next() {
38 // validate.Struct(validFoo)
39 // validate.Struct(invalidFoo)
40 // }
41 // })
42 // }
43
44 func BenchmarkValidateStructLarge(b *testing.B) {
45
46 tFail := &TestString{
47 Required: "",
48 Len: "",
49 Min: "",
50 Max: "12345678901",
51 MinMax: "",
52 Lt: "0123456789",
53 Lte: "01234567890",
54 Gt: "1",
55 Gte: "1",
56 OmitEmpty: "12345678901",
57 Sub: &SubTest{
58 Test: "",
59 },
60 Anonymous: struct {
61 A string `validate:"required"`
62 }{
63 A: "",
64 },
65 Iface: &Impl{
66 F: "12",
67 },
68 }
69
70 tSuccess := &TestString{
71 Required: "Required",
72 Len: "length==10",
73 Min: "min=1",
74 Max: "1234567890",
75 MinMax: "12345",
76 Lt: "012345678",
77 Lte: "0123456789",
78 Gt: "01234567890",
79 Gte: "0123456789",
80 OmitEmpty: "",
81 Sub: &SubTest{
82 Test: "1",
83 },
84 SubIgnore: &SubTest{
85 Test: "",
86 },
87 Anonymous: struct {
88 A string `validate:"required"`
89 }{
90 A: "1",
91 },
92 Iface: &Impl{
93 F: "123",
94 },
95 }
96
97 for n := 0; n < b.N; n++ {
98 validate.Struct(tSuccess)
99 validate.Struct(tFail)
100 }
101 }
102
103 // func BenchmarkTemplateParallelLarge(b *testing.B) {
104
105 // tFail := &TestString{
106 // Required: "",
107 // Len: "",
108 // Min: "",
109 // Max: "12345678901",
110 // MinMax: "",
111 // Lt: "0123456789",
112 // Lte: "01234567890",
113 // Gt: "1",
114 // Gte: "1",
115 // OmitEmpty: "12345678901",
116 // Sub: &SubTest{
117 // Test: "",
118 // },
119 // Anonymous: struct {
120 // A string `validate:"required"`
121 // }{
122 // A: "",
123 // },
124 // Iface: &Impl{
125 // F: "12",
126 // },
127 // }
128
129 // tSuccess := &TestString{
130 // Required: "Required",
131 // Len: "length==10",
132 // Min: "min=1",
133 // Max: "1234567890",
134 // MinMax: "12345",
135 // Lt: "012345678",
136 // Lte: "0123456789",
137 // Gt: "01234567890",
138 // Gte: "0123456789",
139 // OmitEmpty: "",
140 // Sub: &SubTest{
141 // Test: "1",
142 // },
143 // SubIgnore: &SubTest{
144 // Test: "",
145 // },
146 // Anonymous: struct {
147 // A string `validate:"required"`
148 // }{
149 // A: "1",
150 // },
151 // Iface: &Impl{
152 // F: "123",
153 // },
154 // }
155
156 // b.RunParallel(func(pb *testing.PB) {
157 // for pb.Next() {
158 // validate.Struct(tSuccess)
159 // validate.Struct(tFail)
160 // }
161 // })
162 // }
167167 verify it has been assigned.
168168
169169 omitempty
170 Allows conitional validation, for example if a field is not set with
170 Allows conditional validation, for example if a field is not set with
171171 a value (Determined by the required validator) then other validation
172172 such as min or max won't run, but if a value is set validation will run.
173173 (Usage: omitempty)
361361 This validates that a string value does not contain the supplied rune value.
362362 (Usage: excludesrune=@)
363363
364 isbn
365 This validates that a string value contains a valid isbn10 or isbn13 value.
366 (Usage: isbn)
367
368 isbn10
369 This validates that a string value contains a valid isbn10 value.
370 (Usage: isbn10)
371
372 isbn13
373 This validates that a string value contains a valid isbn13 value.
374 (Usage: isbn13)
375
376 uuid
377 This validates that a string value contains a valid UUID.
378 (Usage: uuid)
379
380 uuid3
381 This validates that a string value contains a valid version 3 UUID.
382 (Usage: uuid3)
383
384 uuid4
385 This validates that a string value contains a valid version 4 UUID.
386 (Usage: uuid4)
387
388 uuid5
389 This validates that a string value contains a valid version 5 UUID.
390 (Usage: uuid5)
391
392 ascii
393 This validates that a string value contains only ASCII characters.
394 NOTE: if the string is blank, this validates as true.
395 (Usage: ascii)
396
397 asciiprint
398 This validates that a string value contains only printable ASCII characters.
399 NOTE: if the string is blank, this validates as true.
400 (Usage: asciiprint)
401
402 multibyte
403 This validates that a string value contains one or more multibyte characters.
404 NOTE: if the string is blank, this validates as true.
405 (Usage: multibyte)
406
407 datauri
408 This validates that a string value contains a valid DataURI.
409 NOTE: this will also validate that the data portion is valid base64
410 (Usage: datauri)
411
412 latitude
413 This validates that a string value contains a valid latitude.
414 (Usage: latitude)
415
416 longitude
417 This validates that a string value contains a valid longitude.
418 (Usage: longitude)
419
420 ssn
421 This validates that a string value contains a valid U.S. Social Security Number.
422 (Usage: ssn)
423
364424 Validator notes:
365425
366426 regex
0 package validator_test
1
2 import (
3 "fmt"
4
5 "../validator"
6 )
7
8 func ExampleValidate_new() {
9 validator.New("validate", validator.BakedInValidators)
10 }
11
12 func ExampleValidate_addFunction() {
13 // This should be stored somewhere globally
14 var validate *validator.Validate
15
16 validate = validator.New("validate", validator.BakedInValidators)
17
18 fn := func(top interface{}, current interface{}, field interface{}, param string) bool {
19 return field.(string) == "hello"
20 }
21
22 validate.AddFunction("valueishello", fn)
23
24 message := "hello"
25 err := validate.Field(message, "valueishello")
26 fmt.Println(err)
27 //Output:
28 //<nil>
29 }
30
31 func ExampleValidate_field() {
32 // This should be stored somewhere globally
33 var validate *validator.Validate
34
35 validate = validator.New("validate", validator.BakedInValidators)
36
37 i := 0
38 err := validate.Field(i, "gt=1,lte=10")
39 fmt.Println(err.Field)
40 fmt.Println(err.Tag)
41 fmt.Println(err.Kind) // NOTE: Kind and Type can be different i.e. time Kind=struct and Type=time.Time
42 fmt.Println(err.Type)
43 fmt.Println(err.Param)
44 fmt.Println(err.Value)
45 //Output:
46 //
47 //gt
48 //int
49 //int
50 //1
51 //0
52 }
53
54 func ExampleValidate_struct() {
55 // This should be stored somewhere globally
56 var validate *validator.Validate
57
58 validate = validator.New("validate", validator.BakedInValidators)
59
60 type ContactInformation struct {
61 Phone string `validate:"required"`
62 Street string `validate:"required"`
63 City string `validate:"required"`
64 }
65
66 type User struct {
67 Name string `validate:"required,excludesall=!@#$%^&*()_+-=:;?/0x2C"` // 0x2C = comma (,)
68 Age int8 `validate:"required,gt=0,lt=150"`
69 Email string `validate:"email"`
70 ContactInformation []*ContactInformation
71 }
72
73 contactInfo := &ContactInformation{
74 Street: "26 Here Blvd.",
75 City: "Paradeso",
76 }
77
78 user := &User{
79 Name: "Joey Bloggs",
80 Age: 31,
81 Email: "joeybloggs@gmail.com",
82 ContactInformation: []*ContactInformation{contactInfo},
83 }
84
85 structError := validate.Struct(user)
86 for _, fieldError := range structError.Errors {
87 fmt.Println(fieldError.Field) // Phone
88 fmt.Println(fieldError.Tag) // required
89 //... and so forth
90 //Output:
91 //Phone
92 //required
93 }
94 }
22 import "regexp"
33
44 const (
5 alphaRegexString = "^[a-zA-Z]+$"
6 alphaNumericRegexString = "^[a-zA-Z0-9]+$"
7 numericRegexString = "^[-+]?[0-9]+(?:\\.[0-9]+)?$"
8 numberRegexString = "^[0-9]+$"
9 hexadecimalRegexString = "^[0-9a-fA-F]+$"
10 hexcolorRegexString = "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$"
11 rgbRegexString = "^rgb\\(\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*\\)$"
12 rgbaRegexString = "^rgba\\(\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*((0.[1-9]*)|[01])\\s*\\)$"
13 hslRegexString = "^hsl\\(\\s*(0|[1-9]\\d?|[12]\\d\\d|3[0-5]\\d|360)\\s*,\\s*((0|[1-9]\\d?|100)%)\\s*,\\s*((0|[1-9]\\d?|100)%)\\s*\\)$"
14 hslaRegexString = "^hsla\\(\\s*(0|[1-9]\\d?|[12]\\d\\d|3[0-5]\\d|360)\\s*,\\s*((0|[1-9]\\d?|100)%)\\s*,\\s*((0|[1-9]\\d?|100)%)\\s*,\\s*((0.[1-9]*)|[01])\\s*\\)$"
15 emailRegexString = "^(((([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+(\\.([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+)*)|((\\x22)((((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(([\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(\\([\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}]))))*(((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(\\x22)))@((([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])([a-zA-Z]|\\d|-|\\.|_|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.)+(([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])([a-zA-Z]|\\d|-|\\.|_|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.?$"
16 base64RegexString = "(?:^(?:[A-Za-z0-9+\\/]{4}\\n?)*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+\\/]{3}=)$)"
5 alphaRegexString = "^[a-zA-Z]+$"
6 alphaNumericRegexString = "^[a-zA-Z0-9]+$"
7 numericRegexString = "^[-+]?[0-9]+(?:\\.[0-9]+)?$"
8 numberRegexString = "^[0-9]+$"
9 hexadecimalRegexString = "^[0-9a-fA-F]+$"
10 hexcolorRegexString = "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$"
11 rgbRegexString = "^rgb\\(\\s*(?:(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])|(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%)\\s*\\)$"
12 rgbaRegexString = "^rgba\\(\\s*(?:(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])|(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%)\\s*,\\s*(?:(?:0.[1-9]*)|[01])\\s*\\)$"
13 hslRegexString = "^hsl\\(\\s*(?:0|[1-9]\\d?|[12]\\d\\d|3[0-5]\\d|360)\\s*,\\s*(?:(?:0|[1-9]\\d?|100)%)\\s*,\\s*(?:(?:0|[1-9]\\d?|100)%)\\s*\\)$"
14 hslaRegexString = "^hsla\\(\\s*(?:0|[1-9]\\d?|[12]\\d\\d|3[0-5]\\d|360)\\s*,\\s*(?:(?:0|[1-9]\\d?|100)%)\\s*,\\s*(?:(?:0|[1-9]\\d?|100)%)\\s*,\\s*(?:(?:0.[1-9]*)|[01])\\s*\\)$"
15 emailRegexString = "^(?:(?:(?:(?:[a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+(?:\\.([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+)*)|(?:(?:\\x22)(?:(?:(?:(?:\\x20|\\x09)*(?:\\x0d\\x0a))?(?:\\x20|\\x09)+)?(?:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:\\(?:[\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}]))))*(?:(?:(?:\\x20|\\x09)*(?:\\x0d\\x0a))?(\\x20|\\x09)+)?(?:\\x22)))@(?:(?:(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])(?:[a-zA-Z]|\\d|-|\\.|_|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.)+(?:(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])(?:[a-zA-Z]|\\d|-|\\.|_|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.?$"
16 base64RegexString = "^(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+\\/]{3}=|[A-Za-z0-9+\\/]{4})$"
17 iSBN10RegexString = "^(?:[0-9]{9}X|[0-9]{10})$"
18 iSBN13RegexString = "^(?:(?:97(?:8|9))[0-9]{10})$"
19 uUID3RegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-3[0-9a-f]{3}-[0-9a-f]{4}-[0-9a-f]{12}$"
20 uUID4RegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"
21 uUID5RegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"
22 uUIDRegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
23 aSCIIRegexString = "^[\x00-\x7F]*$"
24 printableASCIIRegexString = "^[\x20-\x7E]*$"
25 multibyteRegexString = "[^\x00-\x7F]"
26 dataURIRegexString = "^data:.+\\/(.+);base64$"
27 latitudeRegexString = "^[-+]?([1-8]?\\d(\\.\\d+)?|90(\\.0+)?)$"
28 longitudeRegexString = "^[-+]?(180(\\.0+)?|((1[0-7]\\d)|([1-9]?\\d))(\\.\\d+)?)$"
29 sSNRegexString = `^\d{3}[- ]?\d{2}[- ]?\d{4}$`
1730 )
1831
1932 var (
20 alphaRegex = regexp.MustCompile(alphaRegexString)
21 alphaNumericRegex = regexp.MustCompile(alphaNumericRegexString)
22 numericRegex = regexp.MustCompile(numericRegexString)
23 numberRegex = regexp.MustCompile(numberRegexString)
24 hexadecimalRegex = regexp.MustCompile(hexadecimalRegexString)
25 hexcolorRegex = regexp.MustCompile(hexcolorRegexString)
26 rgbRegex = regexp.MustCompile(rgbRegexString)
27 rgbaRegex = regexp.MustCompile(rgbaRegexString)
28 hslRegex = regexp.MustCompile(hslRegexString)
29 hslaRegex = regexp.MustCompile(hslaRegexString)
30 emailRegex = regexp.MustCompile(emailRegexString)
31 base64Regex = regexp.MustCompile(base64RegexString)
33 alphaRegex = regexp.MustCompile(alphaRegexString)
34 alphaNumericRegex = regexp.MustCompile(alphaNumericRegexString)
35 numericRegex = regexp.MustCompile(numericRegexString)
36 numberRegex = regexp.MustCompile(numberRegexString)
37 hexadecimalRegex = regexp.MustCompile(hexadecimalRegexString)
38 hexcolorRegex = regexp.MustCompile(hexcolorRegexString)
39 rgbRegex = regexp.MustCompile(rgbRegexString)
40 rgbaRegex = regexp.MustCompile(rgbaRegexString)
41 hslRegex = regexp.MustCompile(hslRegexString)
42 hslaRegex = regexp.MustCompile(hslaRegexString)
43 emailRegex = regexp.MustCompile(emailRegexString)
44 base64Regex = regexp.MustCompile(base64RegexString)
45 iSBN10Regex = regexp.MustCompile(iSBN10RegexString)
46 iSBN13Regex = regexp.MustCompile(iSBN13RegexString)
47 uUID3Regex = regexp.MustCompile(uUID3RegexString)
48 uUID4Regex = regexp.MustCompile(uUID4RegexString)
49 uUID5Regex = regexp.MustCompile(uUID5RegexString)
50 uUIDRegex = regexp.MustCompile(uUIDRegexString)
51 aSCIIRegex = regexp.MustCompile(aSCIIRegexString)
52 printableASCIIRegex = regexp.MustCompile(printableASCIIRegexString)
53 multibyteRegex = regexp.MustCompile(multibyteRegexString)
54 dataURIRegex = regexp.MustCompile(dataURIRegexString)
55 latitudeRegex = regexp.MustCompile(latitudeRegexString)
56 longitudeRegex = regexp.MustCompile(longitudeRegexString)
57 sSNRegex = regexp.MustCompile(sSNRegexString)
3258 )
3359
3460 func matchesRegex(regex *regexp.Regexp, field interface{}) bool {
245245 v.tagName = tagName
246246 }
247247
248 // SetStructPoolMax sets the struct pools max size. this may be usefull for fine grained
248 // SetMaxStructPoolSize sets the struct pools max size. this may be usefull for fine grained
249249 // performance tuning towards your application, however, the default should be fine for
250250 // nearly all cases. only increase if you have a deeply nested struct structure.
251251 // NOTE: this method is not thread-safe
223223 NotEqualSkip(t, 2, val, nil)
224224 EqualSkip(t, 2, val.Field, field)
225225 EqualSkip(t, 2, val.Tag, expectedTag)
226 }
227
228 func TestSSNValidation(t *testing.T) {
229 tests := []struct {
230 param string
231 expected bool
232 }{
233 {"", false},
234 {"00-90-8787", false},
235 {"66690-76", false},
236 {"191 60 2869", true},
237 {"191-60-2869", true},
238 }
239
240 for i, test := range tests {
241
242 err := validate.Field(test.param, "ssn")
243
244 if test.expected == true {
245 if !IsEqual(t, err, nil) {
246 t.Fatalf("Index: %d SSN failed Error: %s", i, err)
247 }
248 } else {
249 if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "ssn") {
250 t.Fatalf("Index: %d SSN failed Error: %s", i, err)
251 }
252 }
253 }
254 }
255
256 func TestLongitudeValidation(t *testing.T) {
257 tests := []struct {
258 param string
259 expected bool
260 }{
261 {"", false},
262 {"-180.000", true},
263 {"180.1", false},
264 {"+73.234", true},
265 {"+382.3811", false},
266 {"23.11111111", true},
267 }
268
269 for i, test := range tests {
270
271 err := validate.Field(test.param, "longitude")
272
273 if test.expected == true {
274 if !IsEqual(t, err, nil) {
275 t.Fatalf("Index: %d Longitude failed Error: %s", i, err)
276 }
277 } else {
278 if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "longitude") {
279 t.Fatalf("Index: %d Longitude failed Error: %s", i, err)
280 }
281 }
282 }
283 }
284
285 func TestLatitudeValidation(t *testing.T) {
286 tests := []struct {
287 param string
288 expected bool
289 }{
290 {"", false},
291 {"-90.000", true},
292 {"+90", true},
293 {"47.1231231", true},
294 {"+99.9", false},
295 {"108", false},
296 }
297
298 for i, test := range tests {
299
300 err := validate.Field(test.param, "latitude")
301
302 if test.expected == true {
303 if !IsEqual(t, err, nil) {
304 t.Fatalf("Index: %d Latitude failed Error: %s", i, err)
305 }
306 } else {
307 if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "latitude") {
308 t.Fatalf("Index: %d Latitude failed Error: %s", i, err)
309 }
310 }
311 }
312 }
313
314 func TestDataURIValidation(t *testing.T) {
315 tests := []struct {
316 param string
317 expected bool
318 }{
319 {"data:image/png;base64,TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4=", true},
320 {"data:text/plain;base64,Vml2YW11cyBmZXJtZW50dW0gc2VtcGVyIHBvcnRhLg==", true},
321 {"image/gif;base64,U3VzcGVuZGlzc2UgbGVjdHVzIGxlbw==", false},
322 {"data:image/gif;base64,MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuMPNS1Ufof9EW/M98FNw" +
323 "UAKrwflsqVxaxQjBQnHQmiI7Vac40t8x7pIb8gLGV6wL7sBTJiPovJ0V7y7oc0Ye" +
324 "rhKh0Rm4skP2z/jHwwZICgGzBvA0rH8xlhUiTvcwDCJ0kc+fh35hNt8srZQM4619" +
325 "FTgB66Xmp4EtVyhpQV+t02g6NzK72oZI0vnAvqhpkxLeLiMCyrI416wHm5Tkukhx" +
326 "QmcL2a6hNOyu0ixX/x2kSFXApEnVrJ+/IxGyfyw8kf4N2IZpW5nEP847lpfj0SZZ" +
327 "Fwrd1mnfnDbYohX2zRptLy2ZUn06Qo9pkG5ntvFEPo9bfZeULtjYzIl6K8gJ2uGZ" + "HQIDAQAB", true},
328 {"data:image/png;base64,12345", false},
329 {"", false},
330 {"data:text,:;base85,U3VzcGVuZGlzc2UgbGVjdHVzIGxlbw==", false},
331 }
332
333 for i, test := range tests {
334
335 err := validate.Field(test.param, "datauri")
336
337 if test.expected == true {
338 if !IsEqual(t, err, nil) {
339 t.Fatalf("Index: %d DataURI failed Error: %s", i, err)
340 }
341 } else {
342 if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "datauri") {
343 t.Fatalf("Index: %d DataURI failed Error: %s", i, err)
344 }
345 }
346 }
347 }
348
349 func TestMultibyteValidation(t *testing.T) {
350 tests := []struct {
351 param string
352 expected bool
353 }{
354 {"", true},
355 {"abc", false},
356 {"123", false},
357 {"<>@;.-=", false},
358 {"ひらがな・カタカナ、.漢字", true},
359 {"あいうえお foobar", true},
360 {"test@example.com", true},
361 {"test@example.com", true},
362 {"1234abcDExyz", true},
363 {"カタカナ", true},
364 }
365
366 for i, test := range tests {
367
368 err := validate.Field(test.param, "multibyte")
369
370 if test.expected == true {
371 if !IsEqual(t, err, nil) {
372 t.Fatalf("Index: %d Multibyte failed Error: %s", i, err)
373 }
374 } else {
375 if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "multibyte") {
376 t.Fatalf("Index: %d Multibyte failed Error: %s", i, err)
377 }
378 }
379 }
380 }
381
382 func TestPrintableASCIIValidation(t *testing.T) {
383 tests := []struct {
384 param string
385 expected bool
386 }{
387 {"", true},
388 {"foobar", false},
389 {"xyz098", false},
390 {"123456", false},
391 {"カタカナ", false},
392 {"foobar", true},
393 {"0987654321", true},
394 {"test@example.com", true},
395 {"1234abcDEF", true},
396 {"newline\n", false},
397 {"\x19test\x7F", false},
398 }
399
400 for i, test := range tests {
401
402 err := validate.Field(test.param, "printascii")
403
404 if test.expected == true {
405 if !IsEqual(t, err, nil) {
406 t.Fatalf("Index: %d Printable ASCII failed Error: %s", i, err)
407 }
408 } else {
409 if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "printascii") {
410 t.Fatalf("Index: %d Printable ASCII failed Error: %s", i, err)
411 }
412 }
413 }
414 }
415
416 func TestASCIIValidation(t *testing.T) {
417 tests := []struct {
418 param string
419 expected bool
420 }{
421 {"", true},
422 {"foobar", false},
423 {"xyz098", false},
424 {"123456", false},
425 {"カタカナ", false},
426 {"foobar", true},
427 {"0987654321", true},
428 {"test@example.com", true},
429 {"1234abcDEF", true},
430 {"", true},
431 }
432
433 for i, test := range tests {
434
435 err := validate.Field(test.param, "ascii")
436
437 if test.expected == true {
438 if !IsEqual(t, err, nil) {
439 t.Fatalf("Index: %d ASCII failed Error: %s", i, err)
440 }
441 } else {
442 if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "ascii") {
443 t.Fatalf("Index: %d ASCII failed Error: %s", i, err)
444 }
445 }
446 }
447 }
448
449 func TestUUID5Validation(t *testing.T) {
450 tests := []struct {
451 param string
452 expected bool
453 }{
454
455 {"", false},
456 {"xxxa987fbc9-4bed-3078-cf07-9141ba07c9f3", false},
457 {"9c858901-8a57-4791-81fe-4c455b099bc9", false},
458 {"a987fbc9-4bed-3078-cf07-9141ba07c9f3", false},
459 {"987fbc97-4bed-5078-af07-9141ba07c9f3", true},
460 {"987fbc97-4bed-5078-9f07-9141ba07c9f3", true},
461 }
462
463 for i, test := range tests {
464
465 err := validate.Field(test.param, "uuid5")
466
467 if test.expected == true {
468 if !IsEqual(t, err, nil) {
469 t.Fatalf("Index: %d UUID5 failed Error: %s", i, err)
470 }
471 } else {
472 if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "uuid5") {
473 t.Fatalf("Index: %d UUID5 failed Error: %s", i, err)
474 }
475 }
476 }
477 }
478
479 func TestUUID4Validation(t *testing.T) {
480 tests := []struct {
481 param string
482 expected bool
483 }{
484 {"", false},
485 {"xxxa987fbc9-4bed-3078-cf07-9141ba07c9f3", false},
486 {"a987fbc9-4bed-5078-af07-9141ba07c9f3", false},
487 {"934859", false},
488 {"57b73598-8764-4ad0-a76a-679bb6640eb1", true},
489 {"625e63f3-58f5-40b7-83a1-a72ad31acffb", true},
490 }
491
492 for i, test := range tests {
493
494 err := validate.Field(test.param, "uuid4")
495
496 if test.expected == true {
497 if !IsEqual(t, err, nil) {
498 t.Fatalf("Index: %d UUID4 failed Error: %s", i, err)
499 }
500 } else {
501 if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "uuid4") {
502 t.Fatalf("Index: %d UUID4 failed Error: %s", i, err)
503 }
504 }
505 }
506 }
507
508 func TestUUID3Validation(t *testing.T) {
509 tests := []struct {
510 param string
511 expected bool
512 }{
513 {"", false},
514 {"412452646", false},
515 {"xxxa987fbc9-4bed-3078-cf07-9141ba07c9f3", false},
516 {"a987fbc9-4bed-4078-8f07-9141ba07c9f3", false},
517 {"a987fbc9-4bed-3078-cf07-9141ba07c9f3", true},
518 }
519
520 for i, test := range tests {
521
522 err := validate.Field(test.param, "uuid3")
523
524 if test.expected == true {
525 if !IsEqual(t, err, nil) {
526 t.Fatalf("Index: %d UUID3 failed Error: %s", i, err)
527 }
528 } else {
529 if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "uuid3") {
530 t.Fatalf("Index: %d UUID3 failed Error: %s", i, err)
531 }
532 }
533 }
534 }
535
536 func TestUUIDValidation(t *testing.T) {
537 tests := []struct {
538 param string
539 expected bool
540 }{
541 {"", false},
542 {"xxxa987fbc9-4bed-3078-cf07-9141ba07c9f3", false},
543 {"a987fbc9-4bed-3078-cf07-9141ba07c9f3xxx", false},
544 {"a987fbc94bed3078cf079141ba07c9f3", false},
545 {"934859", false},
546 {"987fbc9-4bed-3078-cf07a-9141ba07c9f3", false},
547 {"aaaaaaaa-1111-1111-aaag-111111111111", false},
548 {"a987fbc9-4bed-3078-cf07-9141ba07c9f3", true},
549 }
550
551 for i, test := range tests {
552
553 err := validate.Field(test.param, "uuid")
554
555 if test.expected == true {
556 if !IsEqual(t, err, nil) {
557 t.Fatalf("Index: %d UUID failed Error: %s", i, err)
558 }
559 } else {
560 if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "uuid") {
561 t.Fatalf("Index: %d UUID failed Error: %s", i, err)
562 }
563 }
564 }
565 }
566
567 func TestISBNValidation(t *testing.T) {
568 tests := []struct {
569 param string
570 expected bool
571 }{
572 {"", false},
573 {"foo", false},
574 {"3836221195", true},
575 {"1-61729-085-8", true},
576 {"3 423 21412 0", true},
577 {"3 401 01319 X", true},
578 {"9784873113685", true},
579 {"978-4-87311-368-5", true},
580 {"978 3401013190", true},
581 {"978-3-8362-2119-1", true},
582 }
583
584 for i, test := range tests {
585
586 err := validate.Field(test.param, "isbn")
587
588 if test.expected == true {
589 if !IsEqual(t, err, nil) {
590 t.Fatalf("Index: %d ISBN failed Error: %s", i, err)
591 }
592 } else {
593 if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "isbn") {
594 t.Fatalf("Index: %d ISBN failed Error: %s", i, err)
595 }
596 }
597 }
598 }
599
600 func TestISBN13Validation(t *testing.T) {
601 tests := []struct {
602 param string
603 expected bool
604 }{
605 {"", false},
606 {"foo", false},
607 {"3-8362-2119-5", false},
608 {"01234567890ab", false},
609 {"978 3 8362 2119 0", false},
610 {"9784873113685", true},
611 {"978-4-87311-368-5", true},
612 {"978 3401013190", true},
613 {"978-3-8362-2119-1", true},
614 }
615
616 for i, test := range tests {
617
618 err := validate.Field(test.param, "isbn13")
619
620 if test.expected == true {
621 if !IsEqual(t, err, nil) {
622 t.Fatalf("Index: %d ISBN13 failed Error: %s", i, err)
623 }
624 } else {
625 if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "isbn13") {
626 t.Fatalf("Index: %d ISBN13 failed Error: %s", i, err)
627 }
628 }
629 }
630 }
631
632 func TestISBN10Validation(t *testing.T) {
633 tests := []struct {
634 param string
635 expected bool
636 }{
637 {"", false},
638 {"foo", false},
639 {"3423214121", false},
640 {"978-3836221191", false},
641 {"3-423-21412-1", false},
642 {"3 423 21412 1", false},
643 {"3836221195", true},
644 {"1-61729-085-8", true},
645 {"3 423 21412 0", true},
646 {"3 401 01319 X", true},
647 }
648
649 for i, test := range tests {
650
651 err := validate.Field(test.param, "isbn10")
652
653 if test.expected == true {
654 if !IsEqual(t, err, nil) {
655 t.Fatalf("Index: %d ISBN10 failed Error: %s", i, err)
656 }
657 } else {
658 if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "isbn10") {
659 t.Fatalf("Index: %d ISBN10 failed Error: %s", i, err)
660 }
661 }
662 }
226663 }
227664
228665 func TestExcludesRuneValidation(t *testing.T) {
17352172 err = validate.Field(s, "rgba")
17362173 Equal(t, err, nil)
17372174
2175 s = "rgba(12%,55%,100%,0.12)"
2176 err = validate.Field(s, "rgba")
2177 Equal(t, err, nil)
2178
17382179 s = "rgba( 0, 31, 255, 0.5)"
17392180 err = validate.Field(s, "rgba")
17402181 Equal(t, err, nil)
17412182
2183 s = "rgba(12%,55,100%,0.12)"
2184 err = validate.Field(s, "rgba")
2185 NotEqual(t, err, nil)
2186 Equal(t, err.Tag, "rgba")
2187
17422188 s = "rgb(0, 31, 255)"
17432189 err = validate.Field(s, "rgba")
17442190 NotEqual(t, err, nil)
17672213 s = "rgb(0, 31, 255)"
17682214 err = validate.Field(s, "rgb")
17692215 Equal(t, err, nil)
2216
2217 s = "rgb(10%, 50%, 100%)"
2218 err = validate.Field(s, "rgb")
2219 Equal(t, err, nil)
2220
2221 s = "rgb(10%, 50%, 55)"
2222 err = validate.Field(s, "rgb")
2223 NotEqual(t, err, nil)
2224 Equal(t, err.Tag, "rgb")
17702225
17712226 s = "rgb(1,349,275)"
17722227 err = validate.Field(s, "rgb")
23342789
23352790 PanicMatches(t, func() { validate.Field(s.Test, "zzxxBadFunction") }, fmt.Sprintf("Undefined validation function on field %s", ""))
23362791 }
2337
2338 func BenchmarkValidateField(b *testing.B) {
2339 for n := 0; n < b.N; n++ {
2340 validate.Field("1", "len=1")
2341 }
2342 }
2343
2344 func BenchmarkValidateStructSimple(b *testing.B) {
2345
2346 type Foo struct {
2347 StringValue string `validate:"min=5,max=10"`
2348 IntValue int `validate:"min=5,max=10"`
2349 }
2350
2351 validFoo := &Foo{StringValue: "Foobar", IntValue: 7}
2352 invalidFoo := &Foo{StringValue: "Fo", IntValue: 3}
2353
2354 for n := 0; n < b.N; n++ {
2355 validate.Struct(validFoo)
2356 validate.Struct(invalidFoo)
2357 }
2358 }
2359
2360 // func BenchmarkTemplateParallelSimple(b *testing.B) {
2361
2362 // type Foo struct {
2363 // StringValue string `validate:"min=5,max=10"`
2364 // IntValue int `validate:"min=5,max=10"`
2365 // }
2366
2367 // validFoo := &Foo{StringValue: "Foobar", IntValue: 7}
2368 // invalidFoo := &Foo{StringValue: "Fo", IntValue: 3}
2369
2370 // b.RunParallel(func(pb *testing.PB) {
2371 // for pb.Next() {
2372 // validate.Struct(validFoo)
2373 // validate.Struct(invalidFoo)
2374 // }
2375 // })
2376 // }
2377
2378 func BenchmarkValidateStructLarge(b *testing.B) {
2379
2380 tFail := &TestString{
2381 Required: "",
2382 Len: "",
2383 Min: "",
2384 Max: "12345678901",
2385 MinMax: "",
2386 Lt: "0123456789",
2387 Lte: "01234567890",
2388 Gt: "1",
2389 Gte: "1",
2390 OmitEmpty: "12345678901",
2391 Sub: &SubTest{
2392 Test: "",
2393 },
2394 Anonymous: struct {
2395 A string `validate:"required"`
2396 }{
2397 A: "",
2398 },
2399 Iface: &Impl{
2400 F: "12",
2401 },
2402 }
2403
2404 tSuccess := &TestString{
2405 Required: "Required",
2406 Len: "length==10",
2407 Min: "min=1",
2408 Max: "1234567890",
2409 MinMax: "12345",
2410 Lt: "012345678",
2411 Lte: "0123456789",
2412 Gt: "01234567890",
2413 Gte: "0123456789",
2414 OmitEmpty: "",
2415 Sub: &SubTest{
2416 Test: "1",
2417 },
2418 SubIgnore: &SubTest{
2419 Test: "",
2420 },
2421 Anonymous: struct {
2422 A string `validate:"required"`
2423 }{
2424 A: "1",
2425 },
2426 Iface: &Impl{
2427 F: "123",
2428 },
2429 }
2430
2431 for n := 0; n < b.N; n++ {
2432 validate.Struct(tSuccess)
2433 validate.Struct(tFail)
2434 }
2435 }
2436
2437 // func BenchmarkTemplateParallelLarge(b *testing.B) {
2438
2439 // tFail := &TestString{
2440 // Required: "",
2441 // Len: "",
2442 // Min: "",
2443 // Max: "12345678901",
2444 // MinMax: "",
2445 // Lt: "0123456789",
2446 // Lte: "01234567890",
2447 // Gt: "1",
2448 // Gte: "1",
2449 // OmitEmpty: "12345678901",
2450 // Sub: &SubTest{
2451 // Test: "",
2452 // },
2453 // Anonymous: struct {
2454 // A string `validate:"required"`
2455 // }{
2456 // A: "",
2457 // },
2458 // Iface: &Impl{
2459 // F: "12",
2460 // },
2461 // }
2462
2463 // tSuccess := &TestString{
2464 // Required: "Required",
2465 // Len: "length==10",
2466 // Min: "min=1",
2467 // Max: "1234567890",
2468 // MinMax: "12345",
2469 // Lt: "012345678",
2470 // Lte: "0123456789",
2471 // Gt: "01234567890",
2472 // Gte: "0123456789",
2473 // OmitEmpty: "",
2474 // Sub: &SubTest{
2475 // Test: "1",
2476 // },
2477 // SubIgnore: &SubTest{
2478 // Test: "",
2479 // },
2480 // Anonymous: struct {
2481 // A string `validate:"required"`
2482 // }{
2483 // A: "1",
2484 // },
2485 // Iface: &Impl{
2486 // F: "123",
2487 // },
2488 // }
2489
2490 // b.RunParallel(func(pb *testing.PB) {
2491 // for pb.Next() {
2492 // validate.Struct(tSuccess)
2493 // validate.Struct(tFail)
2494 // }
2495 // })
2496 // }