Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 135 additions & 0 deletions baked_in.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,141 @@ var BakedInValidators = map[string]Func{
"excludes": excludes,
"excludesall": excludesAll,
"excludesrune": excludesRune,
"isbn": isISBN,
"isbn10": isISBN10,
"isbn13": isISBN13,
"uuid": isUUID,
"uuid3": isUUID3,
"uuid4": isUUID4,
"uuid5": isUUID5,
"ascii": isASCII,
"printascii": isPrintableASCII,
"multibyte": hasMultiByteCharacter,
"datauri": isDataURI,
"latitude": isLatitude,
"longitude": isLongitude,
"ssn": isSSN,
}

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

if len(field.(string)) != 11 {
return false
}

return matchesRegex(sSNRegex, field)
}

func isLongitude(top interface{}, current interface{}, field interface{}, param string) bool {
return matchesRegex(longitudeRegex, field)
}

func isLatitude(top interface{}, current interface{}, field interface{}, param string) bool {
return matchesRegex(latitudeRegex, field)
}

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

uri := strings.SplitN(field.(string), ",", 2)

if len(uri) != 2 {
return false
}

if !matchesRegex(dataURIRegex, uri[0]) {
return false
}

return isBase64(top, current, uri[1], param)
}

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

if len(field.(string)) == 0 {
return true
}

return matchesRegex(multibyteRegex, field)
}

func isPrintableASCII(top interface{}, current interface{}, field interface{}, param string) bool {
return matchesRegex(printableASCIIRegex, field)
}

func isASCII(top interface{}, current interface{}, field interface{}, param string) bool {
return matchesRegex(aSCIIRegex, field)
}

func isUUID5(top interface{}, current interface{}, field interface{}, param string) bool {
return matchesRegex(uUID5Regex, field)
}

func isUUID4(top interface{}, current interface{}, field interface{}, param string) bool {
return matchesRegex(uUID4Regex, field)
}

func isUUID3(top interface{}, current interface{}, field interface{}, param string) bool {
return matchesRegex(uUID3Regex, field)
}

func isUUID(top interface{}, current interface{}, field interface{}, param string) bool {
return matchesRegex(uUIDRegex, field)
}

func isISBN(top interface{}, current interface{}, field interface{}, param string) bool {
return isISBN10(top, current, field, param) || isISBN13(top, current, field, param)
}

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

s := strings.Replace(strings.Replace(field.(string), "-", "", 4), " ", "", 4)

if !matchesRegex(iSBN13Regex, s) {
return false
}

var checksum int32
var i int32

factor := []int32{1, 3}

for i = 0; i < 12; i++ {
checksum += factor[i%2] * int32(s[i]-'0')
}

if (int32(s[12]-'0'))-((10-(checksum%10))%10) == 0 {
return true
}

return false
}

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

s := strings.Replace(strings.Replace(field.(string), "-", "", 3), " ", "", 3)

if !matchesRegex(iSBN10Regex, s) {
return false
}

var checksum int32
var i int32

for i = 0; i < 9; i++ {
checksum += (i + 1) * int32(s[i]-'0')
}

if s[9] == 'X' {
checksum += 10 * 10
} else {
checksum += 10 * int32(s[9]-'0')
}

if checksum%11 == 0 {
return true
}

return false
}

func excludesRune(top interface{}, current interface{}, field interface{}, param string) bool {
Expand Down
163 changes: 163 additions & 0 deletions benchmarks_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
package validator

import "testing"

func BenchmarkValidateField(b *testing.B) {
for n := 0; n < b.N; n++ {
validate.Field("1", "len=1")
}
}

func BenchmarkValidateStructSimple(b *testing.B) {

type Foo struct {
StringValue string `validate:"min=5,max=10"`
IntValue int `validate:"min=5,max=10"`
}

validFoo := &Foo{StringValue: "Foobar", IntValue: 7}
invalidFoo := &Foo{StringValue: "Fo", IntValue: 3}

for n := 0; n < b.N; n++ {
validate.Struct(validFoo)
validate.Struct(invalidFoo)
}
}

// func BenchmarkTemplateParallelSimple(b *testing.B) {

// type Foo struct {
// StringValue string `validate:"min=5,max=10"`
// IntValue int `validate:"min=5,max=10"`
// }

// validFoo := &Foo{StringValue: "Foobar", IntValue: 7}
// invalidFoo := &Foo{StringValue: "Fo", IntValue: 3}

// b.RunParallel(func(pb *testing.PB) {
// for pb.Next() {
// validate.Struct(validFoo)
// validate.Struct(invalidFoo)
// }
// })
// }

func BenchmarkValidateStructLarge(b *testing.B) {

tFail := &TestString{
Required: "",
Len: "",
Min: "",
Max: "12345678901",
MinMax: "",
Lt: "0123456789",
Lte: "01234567890",
Gt: "1",
Gte: "1",
OmitEmpty: "12345678901",
Sub: &SubTest{
Test: "",
},
Anonymous: struct {
A string `validate:"required"`
}{
A: "",
},
Iface: &Impl{
F: "12",
},
}

tSuccess := &TestString{
Required: "Required",
Len: "length==10",
Min: "min=1",
Max: "1234567890",
MinMax: "12345",
Lt: "012345678",
Lte: "0123456789",
Gt: "01234567890",
Gte: "0123456789",
OmitEmpty: "",
Sub: &SubTest{
Test: "1",
},
SubIgnore: &SubTest{
Test: "",
},
Anonymous: struct {
A string `validate:"required"`
}{
A: "1",
},
Iface: &Impl{
F: "123",
},
}

for n := 0; n < b.N; n++ {
validate.Struct(tSuccess)
validate.Struct(tFail)
}
}

// func BenchmarkTemplateParallelLarge(b *testing.B) {

// tFail := &TestString{
// Required: "",
// Len: "",
// Min: "",
// Max: "12345678901",
// MinMax: "",
// Lt: "0123456789",
// Lte: "01234567890",
// Gt: "1",
// Gte: "1",
// OmitEmpty: "12345678901",
// Sub: &SubTest{
// Test: "",
// },
// Anonymous: struct {
// A string `validate:"required"`
// }{
// A: "",
// },
// Iface: &Impl{
// F: "12",
// },
// }

// tSuccess := &TestString{
// Required: "Required",
// Len: "length==10",
// Min: "min=1",
// Max: "1234567890",
// MinMax: "12345",
// Lt: "012345678",
// Lte: "0123456789",
// Gt: "01234567890",
// Gte: "0123456789",
// OmitEmpty: "",
// Sub: &SubTest{
// Test: "1",
// },
// SubIgnore: &SubTest{
// Test: "",
// },
// Anonymous: struct {
// A string `validate:"required"`
// }{
// A: "1",
// },
// Iface: &Impl{
// F: "123",
// },
// }

// b.RunParallel(func(pb *testing.PB) {
// for pb.Next() {
// validate.Struct(tSuccess)
// validate.Struct(tFail)
// }
// })
// }
62 changes: 61 additions & 1 deletion doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ Here is a list of the current built in validators:
verify it has been assigned.

omitempty
Allows conitional validation, for example if a field is not set with
Allows conditional validation, for example if a field is not set with
a value (Determined by the required validator) then other validation
such as min or max won't run, but if a value is set validation will run.
(Usage: omitempty)
Expand Down Expand Up @@ -362,6 +362,66 @@ Here is a list of the current built in validators:
This validates that a string value does not contain the supplied rune value.
(Usage: excludesrune=@)

isbn
This validates that a string value contains a valid isbn10 or isbn13 value.
(Usage: isbn)

isbn10
This validates that a string value contains a valid isbn10 value.
(Usage: isbn10)

isbn13
This validates that a string value contains a valid isbn13 value.
(Usage: isbn13)

uuid
This validates that a string value contains a valid UUID.
(Usage: uuid)

uuid3
This validates that a string value contains a valid version 3 UUID.
(Usage: uuid3)

uuid4
This validates that a string value contains a valid version 4 UUID.
(Usage: uuid4)

uuid5
This validates that a string value contains a valid version 5 UUID.
(Usage: uuid5)

ascii
This validates that a string value contains only ASCII characters.
NOTE: if the string is blank, this validates as true.
(Usage: ascii)

asciiprint
This validates that a string value contains only printable ASCII characters.
NOTE: if the string is blank, this validates as true.
(Usage: asciiprint)

multibyte
This validates that a string value contains one or more multibyte characters.
NOTE: if the string is blank, this validates as true.
(Usage: multibyte)

datauri
This validates that a string value contains a valid DataURI.
NOTE: this will also validate that the data portion is valid base64
(Usage: datauri)

latitude
This validates that a string value contains a valid latitude.
(Usage: latitude)

longitude
This validates that a string value contains a valid longitude.
(Usage: longitude)

ssn
This validates that a string value contains a valid U.S. Social Security Number.
(Usage: ssn)

Validator notes:

regex
Expand Down
Loading