mirror of
https://github.com/Fishwaldo/validator.git
synced 2025-07-06 13:09:48 +00:00
added many new validator + tests + documentation:
ascii printascii multibyte datauri latitude longitude ssn
This commit is contained in:
parent
7aa70841bc
commit
35aff710e4
4 changed files with 359 additions and 37 deletions
56
baked_in.go
56
baked_in.go
|
@ -57,6 +57,62 @@ var BakedInValidators = map[string]Func{
|
|||
"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 {
|
||||
|
|
34
doc.go
34
doc.go
|
@ -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)
|
||||
|
@ -390,6 +390,38 @@ Here is a list of the current built in validators:
|
|||
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
|
||||
|
|
16
regexes.go
16
regexes.go
|
@ -14,13 +14,20 @@ const (
|
|||
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*\\)$"
|
||||
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*\\)$"
|
||||
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}])))\\.?$"
|
||||
base64RegexString = "(?:^(?:[A-Za-z0-9+\\/]{4}\\n?)*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+\\/]{3}=)$)"
|
||||
base64RegexString = "^(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+\\/]{3}=|[A-Za-z0-9+\\/]{4})$"
|
||||
iSBN10RegexString = "^(?:[0-9]{9}X|[0-9]{10})$"
|
||||
iSBN13RegexString = "^(?:(?:97(?:8|9))[0-9]{10})$"
|
||||
uUID3RegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-3[0-9a-f]{3}-[0-9a-f]{4}-[0-9a-f]{12}$"
|
||||
uUID4RegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"
|
||||
uUID5RegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"
|
||||
uUIDRegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
|
||||
aSCIIRegexString = "^[\x00-\x7F]*$"
|
||||
printableASCIIRegexString = "^[\x20-\x7E]*$"
|
||||
multibyteRegexString = "[^\x00-\x7F]"
|
||||
dataURIRegexString = "^data:.+\\/(.+);base64$"
|
||||
latitudeRegexString = "^[-+]?([1-8]?\\d(\\.\\d+)?|90(\\.0+)?)$"
|
||||
longitudeRegexString = "^[-+]?(180(\\.0+)?|((1[0-7]\\d)|([1-9]?\\d))(\\.\\d+)?)$"
|
||||
sSNRegexString = `^\d{3}[- ]?\d{2}[- ]?\d{4}$`
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -42,6 +49,13 @@ var (
|
|||
uUID4Regex = regexp.MustCompile(uUID4RegexString)
|
||||
uUID5Regex = regexp.MustCompile(uUID5RegexString)
|
||||
uUIDRegex = regexp.MustCompile(uUIDRegexString)
|
||||
aSCIIRegex = regexp.MustCompile(aSCIIRegexString)
|
||||
printableASCIIRegex = regexp.MustCompile(printableASCIIRegexString)
|
||||
multibyteRegex = regexp.MustCompile(multibyteRegexString)
|
||||
dataURIRegex = regexp.MustCompile(dataURIRegexString)
|
||||
latitudeRegex = regexp.MustCompile(latitudeRegexString)
|
||||
longitudeRegex = regexp.MustCompile(longitudeRegexString)
|
||||
sSNRegex = regexp.MustCompile(sSNRegexString)
|
||||
)
|
||||
|
||||
func matchesRegex(regex *regexp.Regexp, field interface{}) bool {
|
||||
|
|
|
@ -226,6 +226,226 @@ func AssertMapFieldError(t *testing.T, s map[string]*FieldError, field string, e
|
|||
EqualSkip(t, 2, val.Tag, expectedTag)
|
||||
}
|
||||
|
||||
func TestSSNValidation(t *testing.T) {
|
||||
tests := []struct {
|
||||
param string
|
||||
expected bool
|
||||
}{
|
||||
{"", false},
|
||||
{"00-90-8787", false},
|
||||
{"66690-76", false},
|
||||
{"191 60 2869", true},
|
||||
{"191-60-2869", true},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
|
||||
err := validate.Field(test.param, "ssn")
|
||||
|
||||
if test.expected == true {
|
||||
if !IsEqual(t, err, nil) {
|
||||
t.Fatalf("Index: %d SSN failed Error: %s", i, err)
|
||||
}
|
||||
} else {
|
||||
if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "ssn") {
|
||||
t.Fatalf("Index: %d SSN failed Error: %s", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLongitudeValidation(t *testing.T) {
|
||||
tests := []struct {
|
||||
param string
|
||||
expected bool
|
||||
}{
|
||||
{"", false},
|
||||
{"-180.000", true},
|
||||
{"180.1", false},
|
||||
{"+73.234", true},
|
||||
{"+382.3811", false},
|
||||
{"23.11111111", true},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
|
||||
err := validate.Field(test.param, "longitude")
|
||||
|
||||
if test.expected == true {
|
||||
if !IsEqual(t, err, nil) {
|
||||
t.Fatalf("Index: %d Longitude failed Error: %s", i, err)
|
||||
}
|
||||
} else {
|
||||
if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "longitude") {
|
||||
t.Fatalf("Index: %d Longitude failed Error: %s", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLatitudeValidation(t *testing.T) {
|
||||
tests := []struct {
|
||||
param string
|
||||
expected bool
|
||||
}{
|
||||
{"", false},
|
||||
{"-90.000", true},
|
||||
{"+90", true},
|
||||
{"47.1231231", true},
|
||||
{"+99.9", false},
|
||||
{"108", false},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
|
||||
err := validate.Field(test.param, "latitude")
|
||||
|
||||
if test.expected == true {
|
||||
if !IsEqual(t, err, nil) {
|
||||
t.Fatalf("Index: %d Latitude failed Error: %s", i, err)
|
||||
}
|
||||
} else {
|
||||
if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "latitude") {
|
||||
t.Fatalf("Index: %d Latitude failed Error: %s", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDataURIValidation(t *testing.T) {
|
||||
tests := []struct {
|
||||
param string
|
||||
expected bool
|
||||
}{
|
||||
{"data:image/png;base64,TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4=", true},
|
||||
{"data:text/plain;base64,Vml2YW11cyBmZXJtZW50dW0gc2VtcGVyIHBvcnRhLg==", true},
|
||||
{"image/gif;base64,U3VzcGVuZGlzc2UgbGVjdHVzIGxlbw==", false},
|
||||
{"data:image/gif;base64,MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuMPNS1Ufof9EW/M98FNw" +
|
||||
"UAKrwflsqVxaxQjBQnHQmiI7Vac40t8x7pIb8gLGV6wL7sBTJiPovJ0V7y7oc0Ye" +
|
||||
"rhKh0Rm4skP2z/jHwwZICgGzBvA0rH8xlhUiTvcwDCJ0kc+fh35hNt8srZQM4619" +
|
||||
"FTgB66Xmp4EtVyhpQV+t02g6NzK72oZI0vnAvqhpkxLeLiMCyrI416wHm5Tkukhx" +
|
||||
"QmcL2a6hNOyu0ixX/x2kSFXApEnVrJ+/IxGyfyw8kf4N2IZpW5nEP847lpfj0SZZ" +
|
||||
"Fwrd1mnfnDbYohX2zRptLy2ZUn06Qo9pkG5ntvFEPo9bfZeULtjYzIl6K8gJ2uGZ" + "HQIDAQAB", true},
|
||||
{"data:image/png;base64,12345", false},
|
||||
{"", false},
|
||||
{"data:text,:;base85,U3VzcGVuZGlzc2UgbGVjdHVzIGxlbw==", false},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
|
||||
err := validate.Field(test.param, "datauri")
|
||||
|
||||
if test.expected == true {
|
||||
if !IsEqual(t, err, nil) {
|
||||
t.Fatalf("Index: %d DataURI failed Error: %s", i, err)
|
||||
}
|
||||
} else {
|
||||
if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "datauri") {
|
||||
t.Fatalf("Index: %d DataURI failed Error: %s", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultibyteValidation(t *testing.T) {
|
||||
tests := []struct {
|
||||
param string
|
||||
expected bool
|
||||
}{
|
||||
{"abc", false},
|
||||
{"123", false},
|
||||
{"<>@;.-=", false},
|
||||
{"ひらがな・カタカナ、.漢字", true},
|
||||
{"あいうえお foobar", true},
|
||||
{"test@example.com", true},
|
||||
{"test@example.com", true},
|
||||
{"1234abcDExyz", true},
|
||||
{"カタカナ", true},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
|
||||
err := validate.Field(test.param, "multibyte")
|
||||
|
||||
if test.expected == true {
|
||||
if !IsEqual(t, err, nil) {
|
||||
t.Fatalf("Index: %d Multibyte failed Error: %s", i, err)
|
||||
}
|
||||
} else {
|
||||
if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "multibyte") {
|
||||
t.Fatalf("Index: %d Multibyte failed Error: %s", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrintableASCIIValidation(t *testing.T) {
|
||||
tests := []struct {
|
||||
param string
|
||||
expected bool
|
||||
}{
|
||||
{"", true},
|
||||
{"foobar", false},
|
||||
{"xyz098", false},
|
||||
{"123456", false},
|
||||
{"カタカナ", false},
|
||||
{"foobar", true},
|
||||
{"0987654321", true},
|
||||
{"test@example.com", true},
|
||||
{"1234abcDEF", true},
|
||||
{"newline\n", false},
|
||||
{"\x19test\x7F", false},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
|
||||
err := validate.Field(test.param, "printascii")
|
||||
|
||||
if test.expected == true {
|
||||
if !IsEqual(t, err, nil) {
|
||||
t.Fatalf("Index: %d Printable ASCII failed Error: %s", i, err)
|
||||
}
|
||||
} else {
|
||||
if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "printascii") {
|
||||
t.Fatalf("Index: %d Printable ASCII failed Error: %s", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestASCIIValidation(t *testing.T) {
|
||||
tests := []struct {
|
||||
param string
|
||||
expected bool
|
||||
}{
|
||||
{"", true},
|
||||
{"foobar", false},
|
||||
{"xyz098", false},
|
||||
{"123456", false},
|
||||
{"カタカナ", false},
|
||||
{"foobar", true},
|
||||
{"0987654321", true},
|
||||
{"test@example.com", true},
|
||||
{"1234abcDEF", true},
|
||||
{"", true},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
|
||||
err := validate.Field(test.param, "ascii")
|
||||
|
||||
if test.expected == true {
|
||||
if !IsEqual(t, err, nil) {
|
||||
t.Fatalf("Index: %d ASCII failed Error: %s", i, err)
|
||||
}
|
||||
} else {
|
||||
if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "ascii") {
|
||||
t.Fatalf("Index: %d ASCII failed Error: %s", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUUID5Validation(t *testing.T) {
|
||||
tests := []struct {
|
||||
param string
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue