├── .gitignore ├── .travis.yml ├── README.md ├── validate.go ├── validate_test.go └── validators ├── bytes_are_present.go ├── bytes_are_present_test.go ├── common.go ├── common_test.go ├── email_is_present.go ├── email_is_present_test.go ├── func_validator.go ├── func_validator_test.go ├── int_array_is_present.go ├── int_array_is_present_test.go ├── int_is_greater_than.go ├── int_is_greater_than_test.go ├── int_is_less_than.go ├── int_is_less_than_test.go ├── int_is_present.go ├── int_is_present_test.go ├── regex_match.go ├── regex_match_test.go ├── string_inclusion.go ├── string_inclusion_test.go ├── string_is_present.go ├── string_is_present_test.go ├── string_length_in_range.go ├── string_length_in_range_test.go ├── strings_match.go ├── strings_match_test.go ├── time_after_time.go ├── time_after_time_test.go ├── time_is_before_time.go ├── time_is_before_time_test.go ├── time_is_present.go ├── time_is_present_test.go ├── url_is_present.go ├── url_is_present_test.go ├── uuid_is_present.go └── uuid_is_present_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | .DS_Store 3 | doc 4 | tmp 5 | pkg 6 | *.gem 7 | *.pid 8 | coverage 9 | coverage.data 10 | build/* 11 | *.pbxuser 12 | *.mode1v3 13 | .svn 14 | profile 15 | .console_history 16 | .sass-cache/* 17 | .rake_tasks~ 18 | *.log.lck 19 | solr/ 20 | .jhw-cache/ 21 | jhw.* 22 | *.sublime* 23 | node_modules/ 24 | dist/ 25 | generated/ 26 | .idea 27 | .vendor/ 28 | bin/* 29 | gin-bin 30 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go: 3 | - 1.7 4 | - 1.8 5 | 6 | script: 7 | - go test -v ./... -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # github.com/markbates/validate 2 | [![Build Status](https://travis-ci.org/markbates/validate.svg?branch=master)](https://travis-ci.org/markbates/validate) 3 | 4 | This package provides a framework for writing validations for Go applications. It does not, however, provide you with any actual validators, that part is up to you. 5 | 6 | ## Installation 7 | 8 | ```bash 9 | $ go get github.com/markbates/validate 10 | ``` 11 | 12 | ## Usage 13 | 14 | Using validate is pretty easy, just define some `Validator` objects and away you go. 15 | 16 | Here is a pretty simple example: 17 | 18 | ```go 19 | package main 20 | 21 | import ( 22 | "log" 23 | 24 | v "github.com/markbates/validate" 25 | ) 26 | 27 | type User struct { 28 | Name string 29 | Email string 30 | } 31 | 32 | func (u *User) IsValid(errors *v.Errors) { 33 | if u.Name == "" { 34 | errors.Add("name", "Name must not be blank!") 35 | } 36 | if u.Email == "" { 37 | errors.Add("email", "Email must not be blank!") 38 | } 39 | } 40 | 41 | func main() { 42 | u := User{Name: "", Email: ""} 43 | errors := v.Validate(&u) 44 | log.Println(errors.Errors) 45 | // map[name:[Name must not be blank!] email:[Email must not be blank!]] 46 | } 47 | ``` 48 | 49 | In the previous example I wrote a single `Validator` for the `User` struct. To really get the benefit of using go-validator, as well as the Go language, I would recommend creating distinct validators for each thing you want to validate, that way they can be run concurrently. 50 | 51 | ```go 52 | package main 53 | 54 | import ( 55 | "fmt" 56 | "log" 57 | "strings" 58 | 59 | v "github.com/markbates/validate" 60 | ) 61 | 62 | type User struct { 63 | Name string 64 | Email string 65 | } 66 | 67 | type PresenceValidator struct { 68 | Field string 69 | Value string 70 | } 71 | 72 | func (v *PresenceValidator) IsValid(errors *v.Errors) { 73 | if v.Value == "" { 74 | errors.Add(strings.ToLower(v.Field), fmt.Sprintf("%s must not be blank!", v.Field)) 75 | } 76 | } 77 | 78 | func main() { 79 | u := User{Name: "", Email: ""} 80 | errors := v.Validate(&PresenceValidator{"Email", u.Email}, &PresenceValidator{"Name", u.Name}) 81 | log.Println(errors.Errors) 82 | // map[name:[Name must not be blank!] email:[Email must not be blank!]] 83 | } 84 | ``` 85 | 86 | That's really it. Pretty simple and straight-forward Just a nice clean framework for writing your own validators. Use in good health. 87 | -------------------------------------------------------------------------------- /validate.go: -------------------------------------------------------------------------------- 1 | package validate 2 | /* 3 | This package has moved to github.com/gobuffalo/validate please use that instead. 4 | */ 5 | import ( 6 | "encoding/json" 7 | "encoding/xml" 8 | "strings" 9 | "sync" 10 | 11 | "github.com/markbates/going/wait" 12 | ) 13 | 14 | // Errors holds onto all of the error messages 15 | // that get generated during the validation process. 16 | type Errors struct { 17 | Errors map[string][]string `json:"errors" xml:"errors"` 18 | Lock *sync.RWMutex `json:"-"` 19 | } 20 | 21 | func (e Errors) MarshalXML(enc *xml.Encoder, start xml.StartElement) error { 22 | start.Name = xml.Name{Local: "errors"} 23 | tokens := []xml.Token{start} 24 | 25 | for name, messages := range e.Errors { 26 | outer := xml.StartElement{Name: xml.Name{Local: name}} 27 | 28 | tks := []xml.Token{outer} 29 | for _, m := range messages { 30 | t := xml.StartElement{Name: xml.Name{Local: "message"}} 31 | tks = append(tks, t, xml.CharData(m), xml.EndElement{Name: xml.Name{Local: "message"}}) 32 | } 33 | 34 | tokens = append(tokens, tks...) 35 | tokens = append(tokens, xml.EndElement{Name: outer.Name}) 36 | } 37 | 38 | tokens = append(tokens, xml.EndElement{Name: start.Name}) 39 | 40 | for _, t := range tokens { 41 | err := enc.EncodeToken(t) 42 | if err != nil { 43 | return err 44 | } 45 | } 46 | 47 | // flush to ensure tokens are written 48 | return enc.Flush() 49 | } 50 | 51 | // Validator must be implemented in order to pass the 52 | // validator object into the Validate function. 53 | type Validator interface { 54 | IsValid(errors *Errors) 55 | } 56 | 57 | type vfWrapper struct { 58 | vf func(errors *Errors) 59 | } 60 | 61 | func (v vfWrapper) IsValid(errors *Errors) { 62 | v.vf(errors) 63 | } 64 | 65 | // ValidatorFunc wraps any function in a "Validator" to make 66 | // it easy to write custom ones. 67 | func ValidatorFunc(fn func(errors *Errors)) Validator { 68 | return vfWrapper{fn} 69 | } 70 | 71 | // NewErrors returns a pointer to a Errors 72 | // object that has been primed and ready to go. 73 | func NewErrors() *Errors { 74 | return &Errors{ 75 | Errors: make(map[string][]string), 76 | Lock: new(sync.RWMutex), 77 | } 78 | } 79 | 80 | // Error implements the error interface 81 | func (v *Errors) Error() string { 82 | errs := []string{} 83 | for _, v := range v.Errors { 84 | errs = append(errs, v...) 85 | } 86 | return strings.Join(errs, "\n") 87 | } 88 | 89 | // Count returns the number of errors. 90 | func (v *Errors) Count() int { 91 | return len(v.Errors) 92 | } 93 | 94 | // HasAny returns true/false depending on whether any errors 95 | // have been tracked. 96 | func (v *Errors) HasAny() bool { 97 | return v.Count() > 0 98 | } 99 | 100 | // Append concatenates two Errors objects together. 101 | // This will modify the first object in place. 102 | func (v *Errors) Append(ers *Errors) { 103 | for key, value := range ers.Errors { 104 | for _, msg := range value { 105 | v.Add(key, msg) 106 | } 107 | } 108 | } 109 | 110 | // Add will add a new message to the list of errors using 111 | // the given key. If the key already exists the message will 112 | // be appended to the array of the existing messages. 113 | func (v *Errors) Add(key string, msg string) { 114 | v.Lock.Lock() 115 | v.Errors[key] = append(v.Errors[key], msg) 116 | v.Lock.Unlock() 117 | } 118 | 119 | // Get returns an array of error messages for the given key. 120 | func (v *Errors) Get(key string) []string { 121 | return v.Errors[key] 122 | } 123 | 124 | func (v *Errors) String() string { 125 | b, _ := json.Marshal(v) 126 | return string(b) 127 | } 128 | 129 | // Keys return all field names which have error 130 | func (v *Errors) Keys() []string { 131 | keys := []string{} 132 | for key := range v.Errors { 133 | keys = append(keys, key) 134 | } 135 | 136 | return keys 137 | } 138 | 139 | // Validate takes in n number of Validator objects and will run 140 | // them and return back a point to a Errors object that 141 | // will contain any errors. 142 | func Validate(validators ...Validator) *Errors { 143 | errors := NewErrors() 144 | 145 | wait.Wait(len(validators), func(index int) { 146 | validator := validators[index] 147 | validator.IsValid(errors) 148 | }) 149 | 150 | return errors 151 | } 152 | -------------------------------------------------------------------------------- /validate_test.go: -------------------------------------------------------------------------------- 1 | package validate_test 2 | 3 | import ( 4 | "encoding/xml" 5 | "testing" 6 | 7 | . "github.com/markbates/validate" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | type v1 struct{} 12 | 13 | func (v *v1) IsValid(errors *Errors) { 14 | errors.Add("v1", "there's an error with v1") 15 | } 16 | 17 | type v2 struct{} 18 | 19 | func (v *v2) IsValid(errors *Errors) { 20 | errors.Add("v2", "there's an error with v2") 21 | } 22 | 23 | func TestValidate(t *testing.T) { 24 | r := require.New(t) 25 | 26 | errors := Validate(&v1{}, &v2{}) 27 | r.Equal(errors.Count(), 2) 28 | r.Equal(errors.HasAny(), true) 29 | r.Equal(errors.Errors["v1"], []string{"there's an error with v1"}) 30 | r.Equal(errors.Errors["v2"], []string{"there's an error with v2"}) 31 | 32 | r.Equal(errors.String(), `{"errors":{"v1":["there's an error with v1"],"v2":["there's an error with v2"]}}`) 33 | } 34 | 35 | func TestErrorsKeys(t *testing.T) { 36 | r := require.New(t) 37 | errors := Validate(&v1{}, &v2{}) 38 | r.Contains(errors.Keys(), "v1") 39 | r.Contains(errors.Keys(), "v2") 40 | } 41 | 42 | func Test_ErrorsXML(t *testing.T) { 43 | r := require.New(t) 44 | 45 | errors := Errors{ 46 | Errors: map[string][]string{ 47 | "name": []string{"name1", "name2"}, 48 | "email": []string{"emailA", "emailB"}, 49 | }, 50 | } 51 | 52 | x, err := xml.Marshal(errors) 53 | r.NoError(err) 54 | r.Contains(string(x), "") 55 | r.Contains(string(x), "emailA") 56 | } 57 | -------------------------------------------------------------------------------- /validators/bytes_are_present.go: -------------------------------------------------------------------------------- 1 | package validators 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/markbates/validate" 7 | ) 8 | 9 | type BytesArePresent struct { 10 | Name string 11 | Field []byte 12 | } 13 | 14 | func (v *BytesArePresent) IsValid(errors *validate.Errors) { 15 | if len(v.Field) == 0 { 16 | errors.Add(GenerateKey(v.Name), fmt.Sprintf("%s can not be blank.", v.Name)) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /validators/bytes_are_present_test.go: -------------------------------------------------------------------------------- 1 | package validators_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/markbates/validate" 7 | . "github.com/markbates/validate/validators" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | func Test_BytesArePresent(t *testing.T) { 12 | r := require.New(t) 13 | 14 | v := BytesArePresent{"Name", []byte("Mark")} 15 | errors := validate.NewErrors() 16 | v.IsValid(errors) 17 | r.Equal(errors.Count(), 0) 18 | 19 | v = BytesArePresent{"Name", []byte("")} 20 | v.IsValid(errors) 21 | r.Equal(errors.Count(), 1) 22 | r.Equal(errors.Get("name"), []string{"Name can not be blank."}) 23 | } 24 | -------------------------------------------------------------------------------- /validators/common.go: -------------------------------------------------------------------------------- 1 | package validators 2 | 3 | import ( 4 | "strings" 5 | 6 | "github.com/serenize/snaker" 7 | ) 8 | 9 | var CustomKeys = map[string]string{} 10 | 11 | func GenerateKey(s string) string { 12 | key := CustomKeys[s] 13 | if key != "" { 14 | return key 15 | } 16 | key = strings.Replace(s, " ", "", -1) 17 | key = strings.Replace(key, "-", "", -1) 18 | key = snaker.CamelToSnake(key) 19 | return key 20 | } 21 | -------------------------------------------------------------------------------- /validators/common_test.go: -------------------------------------------------------------------------------- 1 | package validators_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/markbates/validate/validators" 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func Test_GenerateKey(t *testing.T) { 11 | r := require.New(t) 12 | 13 | r.Equal("foo", validators.GenerateKey("Foo")) 14 | r.Equal("created_at", validators.GenerateKey("CreatedAt")) 15 | r.Equal("created_at", validators.GenerateKey("Created At")) 16 | r.Equal("person_id", validators.GenerateKey("PersonID")) 17 | r.Equal("content_type", validators.GenerateKey("Content-Type")) 18 | 19 | validators.CustomKeys["ODGroupIDs"] = "od_group_ids" 20 | r.Equal("od_group_ids", validators.GenerateKey("ODGroupIDs")) 21 | } 22 | -------------------------------------------------------------------------------- /validators/email_is_present.go: -------------------------------------------------------------------------------- 1 | package validators 2 | 3 | import ( 4 | "fmt" 5 | "regexp" 6 | "strings" 7 | 8 | "github.com/markbates/validate" 9 | ) 10 | 11 | var rxEmail *regexp.Regexp 12 | 13 | func init() { 14 | rxEmail = regexp.MustCompile("^(((([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}])))\\.?$") 15 | } 16 | 17 | type EmailIsPresent struct { 18 | Name string 19 | Field string 20 | Message string 21 | } 22 | 23 | // IsValid performs the validation based on the email regexp match. 24 | func (v *EmailIsPresent) IsValid(errors *validate.Errors) { 25 | if !rxEmail.Match([]byte(v.Field)) { 26 | if v.Message == "" { 27 | v.Message = fmt.Sprintf("%s does not match the email format.", v.Name) 28 | } 29 | errors.Add(GenerateKey(v.Name), v.Message) 30 | } 31 | } 32 | 33 | // EmailLike checks that email has two parts (username and domain separated by @) 34 | // Also it check that domain have domain zone (don`t check that zone is valid) 35 | type EmailLike struct { 36 | Name string 37 | Field string 38 | Message string 39 | } 40 | 41 | // IsValid performs the validation based on email struct (username@domain) 42 | func (v *EmailLike) IsValid(errors *validate.Errors) { 43 | parts := strings.Split(v.Field, "@") 44 | if len(parts) != 2 || len(parts[0]) == 0 || len(parts[1]) == 0 { 45 | if v.Message == "" { 46 | v.Message = fmt.Sprintf("%s does not match the email format.", v.Name) 47 | } 48 | errors.Add(GenerateKey(v.Name), v.Message) 49 | } else if len(parts) == 2 { 50 | domain := parts[1] 51 | // Check that domain is valid 52 | if len(strings.Split(domain, ".")) < 2 { 53 | if v.Message == "" { 54 | v.Message = fmt.Sprintf("%s does not match the email format (email domain).", v.Name) 55 | } 56 | errors.Add(GenerateKey(v.Name), v.Message) 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /validators/email_is_present_test.go: -------------------------------------------------------------------------------- 1 | package validators_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/markbates/validate" 7 | . "github.com/markbates/validate/validators" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | func Test_EmailIsPresent(t *testing.T) { 12 | r := require.New(t) 13 | 14 | var tests = []struct { 15 | email string 16 | valid bool 17 | }{ 18 | {"", false}, 19 | {"foo@bar.com", true}, 20 | {"x@x.x", true}, 21 | {"foo@bar.com.au", true}, 22 | {"foo+bar@bar.com", true}, 23 | {"foo@bar.coffee", true}, 24 | {"foo@bar.中文网", true}, 25 | {"invalidemail@", false}, 26 | {"invalid.com", false}, 27 | {"@invalid.com", false}, 28 | {"test|123@m端ller.com", true}, 29 | {"hans@m端ller.com", true}, 30 | {"hans.m端ller@test.com", true}, 31 | {"NathAn.daVIeS@DomaIn.cOM", true}, 32 | {"NATHAN.DAVIES@DOMAIN.CO.UK", true}, 33 | } 34 | for _, test := range tests { 35 | v := EmailIsPresent{Name: "email", Field: test.email} 36 | errors := validate.NewErrors() 37 | v.IsValid(errors) 38 | r.Equal(test.valid, !errors.HasAny()) 39 | } 40 | } 41 | 42 | func Test_EmailLike(t *testing.T) { 43 | r := require.New(t) 44 | 45 | var tests = []struct { 46 | email string 47 | valid bool 48 | }{ 49 | {"", false}, 50 | {"foo@bar.com", true}, 51 | {"x@x.x", true}, 52 | {"foo@bar.com.au", true}, 53 | {"foo+bar@bar.com", true}, 54 | {"foo@bar.coffee", true}, 55 | {"foo@bar.中文网", true}, 56 | {"invalidemail@", false}, 57 | {"invalid.com", false}, 58 | {"@", false}, 59 | {"@invalid.com", false}, 60 | {"test|123@m端ller.com", true}, 61 | {"hans@m端ller.com", true}, 62 | {"hans.m端ller@test.com", true}, 63 | {"NathAn.daVIeS@DomaIn.cOM", true}, 64 | {"NATHAN.DAVIES@DOMAIN.CO.UK", true}, 65 | } 66 | for _, test := range tests { 67 | v := EmailLike{Name: "email", Field: test.email} 68 | errors := validate.NewErrors() 69 | v.IsValid(errors) 70 | r.Equal(test.valid, !errors.HasAny(), test.email) 71 | } 72 | } 73 | 74 | func BenchmarkEmailIsPresent_IsValid(b *testing.B) { 75 | errors := validate.NewErrors() 76 | for i := 0; i <= b.N; i++ { 77 | v := EmailLike{Name: "email", Field: "email@gmail.com"} 78 | v.IsValid(errors) 79 | } 80 | } 81 | 82 | func BenchmarkEmailLike_IsValid(b *testing.B) { 83 | errors := validate.NewErrors() 84 | for i := 0; i <= b.N; i++ { 85 | v := EmailIsPresent{Name: "email", Field: "email@gmail.com"} 86 | v.IsValid(errors) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /validators/func_validator.go: -------------------------------------------------------------------------------- 1 | package validators 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/markbates/going/defaults" 7 | "github.com/markbates/validate" 8 | ) 9 | 10 | type FuncValidator struct { 11 | Fn func() bool 12 | Field string 13 | Name string 14 | Message string 15 | } 16 | 17 | func (f *FuncValidator) IsValid(verrs *validate.Errors) { 18 | // for backwards compatability 19 | f.Name = defaults.String(f.Name, f.Field) 20 | if !f.Fn() { 21 | verrs.Add(GenerateKey(f.Name), fmt.Sprintf(f.Message, f.Field)) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /validators/func_validator_test.go: -------------------------------------------------------------------------------- 1 | package validators_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/markbates/validate" 7 | "github.com/markbates/validate/validators" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | func Test_FuncValidator(t *testing.T) { 12 | r := require.New(t) 13 | 14 | fv := &validators.FuncValidator{ 15 | Name: "Name", 16 | Field: "Field", 17 | Message: "%s is an invalid name", 18 | Fn: func() bool { 19 | return false 20 | }, 21 | } 22 | 23 | verrs := validate.NewErrors() 24 | fv.IsValid(verrs) 25 | 26 | r.Equal([]string{"Field is an invalid name"}, verrs.Get("name")) 27 | } 28 | 29 | func Test_FuncValidatorNoName(t *testing.T) { 30 | r := require.New(t) 31 | 32 | fv := &validators.FuncValidator{ 33 | Field: "Name", 34 | Message: "%s is invalid", 35 | Fn: func() bool { 36 | return false 37 | }, 38 | } 39 | 40 | verrs := validate.NewErrors() 41 | fv.IsValid(verrs) 42 | 43 | r.Equal([]string{"Name is invalid"}, verrs.Get("name")) 44 | } 45 | -------------------------------------------------------------------------------- /validators/int_array_is_present.go: -------------------------------------------------------------------------------- 1 | package validators 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/markbates/validate" 7 | ) 8 | 9 | type IntArrayIsPresent struct { 10 | Name string 11 | Field []int 12 | } 13 | 14 | func (v *IntArrayIsPresent) IsValid(errors *validate.Errors) { 15 | if len(v.Field) == 0 { 16 | errors.Add(GenerateKey(v.Name), fmt.Sprintf("%s can not be empty.", v.Name)) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /validators/int_array_is_present_test.go: -------------------------------------------------------------------------------- 1 | package validators_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/markbates/validate" 7 | . "github.com/markbates/validate/validators" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | func Test_IntArrayIsPresent(t *testing.T) { 12 | r := require.New(t) 13 | 14 | v := IntArrayIsPresent{"Name", []int{1}} 15 | errors := validate.NewErrors() 16 | v.IsValid(errors) 17 | r.Equal(errors.Count(), 0) 18 | 19 | v = IntArrayIsPresent{"Name", []int{}} 20 | v.IsValid(errors) 21 | r.Equal(errors.Count(), 1) 22 | r.Equal(errors.Get("name"), []string{"Name can not be empty."}) 23 | } 24 | -------------------------------------------------------------------------------- /validators/int_is_greater_than.go: -------------------------------------------------------------------------------- 1 | package validators 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/markbates/validate" 7 | ) 8 | 9 | type IntIsGreaterThan struct { 10 | Name string 11 | Field int 12 | Compared int 13 | } 14 | 15 | func (v *IntIsGreaterThan) IsValid(errors *validate.Errors) { 16 | if !(v.Field > v.Compared) { 17 | errors.Add(GenerateKey(v.Name), fmt.Sprintf("%d is not greater than %d.", v.Field, v.Compared)) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /validators/int_is_greater_than_test.go: -------------------------------------------------------------------------------- 1 | package validators_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/markbates/validate" 7 | . "github.com/markbates/validate/validators" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | func Test_IntIsGreaterThan(t *testing.T) { 12 | r := require.New(t) 13 | 14 | v := IntIsGreaterThan{Name: "Number", Field: 2, Compared: 1} 15 | errors := validate.NewErrors() 16 | v.IsValid(errors) 17 | r.Equal(0, errors.Count()) 18 | 19 | v = IntIsGreaterThan{Name: "number", Field: 1, Compared: 2} 20 | v.IsValid(errors) 21 | r.Equal(1, errors.Count()) 22 | r.Equal(errors.Get("number"), []string{"1 is not greater than 2."}) 23 | } 24 | -------------------------------------------------------------------------------- /validators/int_is_less_than.go: -------------------------------------------------------------------------------- 1 | package validators 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/markbates/validate" 7 | ) 8 | 9 | type IntIsLessThan struct { 10 | Name string 11 | Field int 12 | Compared int 13 | } 14 | 15 | func (v *IntIsLessThan) IsValid(errors *validate.Errors) { 16 | if !(v.Field < v.Compared) { 17 | errors.Add(GenerateKey(v.Name), fmt.Sprintf("%d is not less than %d.", v.Field, v.Compared)) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /validators/int_is_less_than_test.go: -------------------------------------------------------------------------------- 1 | package validators_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/markbates/validate" 7 | . "github.com/markbates/validate/validators" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | func Test_IntIsLessThan(t *testing.T) { 12 | r := require.New(t) 13 | 14 | v := IntIsLessThan{Name: "Number", Field: 1, Compared: 2} 15 | errors := validate.NewErrors() 16 | v.IsValid(errors) 17 | r.Equal(errors.Count(), 0) 18 | 19 | v = IntIsLessThan{Name: "number", Field: 1, Compared: 0} 20 | v.IsValid(errors) 21 | r.Equal(errors.Count(), 1) 22 | r.Equal(errors.Get("number"), []string{"1 is not less than 0."}) 23 | } 24 | -------------------------------------------------------------------------------- /validators/int_is_present.go: -------------------------------------------------------------------------------- 1 | package validators 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/markbates/validate" 7 | ) 8 | 9 | type IntIsPresent struct { 10 | Name string 11 | Field int 12 | } 13 | 14 | func (v *IntIsPresent) IsValid(errors *validate.Errors) { 15 | if v.Field == 0 { 16 | errors.Add(GenerateKey(v.Name), fmt.Sprintf("%s can not be blank.", v.Name)) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /validators/int_is_present_test.go: -------------------------------------------------------------------------------- 1 | package validators_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/markbates/validate" 7 | . "github.com/markbates/validate/validators" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | func Test_IntIsPresent(t *testing.T) { 12 | r := require.New(t) 13 | 14 | v := IntIsPresent{"Name", 1} 15 | errors := validate.NewErrors() 16 | v.IsValid(errors) 17 | r.Equal(errors.Count(), 0) 18 | 19 | v = IntIsPresent{"Name", 0} 20 | v.IsValid(errors) 21 | r.Equal(errors.Count(), 1) 22 | r.Equal(errors.Get("name"), []string{"Name can not be blank."}) 23 | } 24 | -------------------------------------------------------------------------------- /validators/regex_match.go: -------------------------------------------------------------------------------- 1 | package validators 2 | 3 | import ( 4 | "fmt" 5 | "regexp" 6 | 7 | "github.com/markbates/validate" 8 | ) 9 | 10 | // RegexMatch specifies the properties needed by the validation. 11 | type RegexMatch struct { 12 | Name string 13 | Field string 14 | Expr string 15 | } 16 | 17 | // IsValid performs the validation based on the regexp match. 18 | func (v *RegexMatch) IsValid(errors *validate.Errors) { 19 | r := regexp.MustCompile(v.Expr) 20 | if !r.Match([]byte(v.Field)) { 21 | errors.Add(GenerateKey(v.Name), fmt.Sprintf("%s does not match the expected format.", v.Name)) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /validators/regex_match_test.go: -------------------------------------------------------------------------------- 1 | package validators_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/markbates/validate" 7 | . "github.com/markbates/validate/validators" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | func Test_RegexMatch(t *testing.T) { 12 | r := require.New(t) 13 | 14 | v := RegexMatch{"Phone", "555-555-5555", "^([0-9]{3}-[0-9]{3}-[0-9]{4})$"} 15 | errors := validate.NewErrors() 16 | v.IsValid(errors) 17 | r.Equal(errors.Count(), 0) 18 | 19 | v = RegexMatch{"Phone", "123-ab1-1424", "^([0-9]{3}-[0-9]{3}-[0-9]{4})$"} 20 | v.IsValid(errors) 21 | r.Equal(errors.Count(), 1) 22 | r.Equal(errors.Get("phone"), []string{"Phone does not match the expected format."}) 23 | } 24 | -------------------------------------------------------------------------------- /validators/string_inclusion.go: -------------------------------------------------------------------------------- 1 | package validators 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | 7 | "github.com/markbates/validate" 8 | ) 9 | 10 | type StringInclusion struct { 11 | Name string 12 | Field string 13 | List []string 14 | } 15 | 16 | func (v *StringInclusion) IsValid(errors *validate.Errors) { 17 | found := false 18 | for _, l := range v.List { 19 | if l == v.Field { 20 | found = true 21 | break 22 | } 23 | } 24 | if !found { 25 | errors.Add(GenerateKey(v.Name), fmt.Sprintf("%s is not in the list [%s].", v.Name, strings.Join(v.List, ", "))) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /validators/string_inclusion_test.go: -------------------------------------------------------------------------------- 1 | package validators_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/markbates/validate" 7 | . "github.com/markbates/validate/validators" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | func Test_StringInclusion(t *testing.T) { 12 | r := require.New(t) 13 | 14 | l := []string{"Mark", "Bates"} 15 | 16 | v := StringInclusion{"Name", "Mark", l} 17 | errors := validate.NewErrors() 18 | v.IsValid(errors) 19 | r.Equal(errors.Count(), 0) 20 | 21 | v = StringInclusion{"Name", "Foo", l} 22 | v.IsValid(errors) 23 | r.Equal(errors.Count(), 1) 24 | r.Equal(errors.Get("name"), []string{"Name is not in the list [Mark, Bates]."}) 25 | } 26 | -------------------------------------------------------------------------------- /validators/string_is_present.go: -------------------------------------------------------------------------------- 1 | package validators 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | 7 | "github.com/markbates/validate" 8 | ) 9 | 10 | type StringIsPresent struct { 11 | Name string 12 | Field string 13 | } 14 | 15 | func (v *StringIsPresent) IsValid(errors *validate.Errors) { 16 | if strings.TrimSpace(v.Field) == "" { 17 | errors.Add(GenerateKey(v.Name), fmt.Sprintf("%s can not be blank.", v.Name)) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /validators/string_is_present_test.go: -------------------------------------------------------------------------------- 1 | package validators_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/markbates/validate" 7 | . "github.com/markbates/validate/validators" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | func Test_StringIsPresent(t *testing.T) { 12 | r := require.New(t) 13 | 14 | v := StringIsPresent{"Name", "Mark"} 15 | errors := validate.NewErrors() 16 | v.IsValid(errors) 17 | r.Equal(errors.Count(), 0) 18 | 19 | v = StringIsPresent{"Name", ""} 20 | v.IsValid(errors) 21 | r.Equal(errors.Count(), 1) 22 | r.Equal(errors.Get("name"), []string{"Name can not be blank."}) 23 | } 24 | -------------------------------------------------------------------------------- /validators/string_length_in_range.go: -------------------------------------------------------------------------------- 1 | package validators 2 | 3 | import ( 4 | "fmt" 5 | "unicode/utf8" 6 | 7 | "github.com/markbates/validate" 8 | ) 9 | 10 | type StringLengthInRange struct { 11 | Name string 12 | Field string 13 | Min int 14 | Max int 15 | Message string 16 | } 17 | 18 | // IsValid checks that string in range of min:max 19 | // if max not present or it equal to 0 it will be equal to string length 20 | func (v *StringLengthInRange) IsValid(errors *validate.Errors) { 21 | strLength := utf8.RuneCountInString(v.Field) 22 | if v.Max == 0 { 23 | v.Max = strLength 24 | } 25 | if v.Message == "" { 26 | v.Message = fmt.Sprintf("%s not in range(%d, %d)", v.Name, v.Min, v.Max) 27 | } 28 | if !(strLength >= v.Min && strLength <= v.Max) { 29 | errors.Add(GenerateKey(v.Name), v.Message) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /validators/string_length_in_range_test.go: -------------------------------------------------------------------------------- 1 | package validators_test 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/markbates/validate" 8 | . "github.com/markbates/validate/validators" 9 | "github.com/stretchr/testify/require" 10 | ) 11 | 12 | func Test_StringLengthInRange(t *testing.T) { 13 | r := require.New(t) 14 | var tests = []struct { 15 | value string 16 | min int 17 | max int 18 | expected bool 19 | }{ 20 | {"123456", 0, 100, true}, 21 | {"1239999", 0, 0, true}, 22 | {"1239asdfasf99", 100, 200, false}, 23 | {"1239999asdff29", 10, 30, true}, 24 | {"あいうえお", 0, 5, true}, 25 | {"あいうえおか", 0, 5, false}, 26 | {"あいうえお", 0, 0, true}, 27 | {"あいうえ", 5, 10, false}, 28 | } 29 | 30 | for _, test := range tests { 31 | v := StringLengthInRange{Name: "email", Field: test.value, Min: test.min, Max: test.max} 32 | errors := validate.NewErrors() 33 | v.IsValid(errors) 34 | r.Equal(test.expected, !errors.HasAny(), fmt.Sprintf("Value: %s, Min:%d, Max:%d", test.value, test.min, test.max)) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /validators/strings_match.go: -------------------------------------------------------------------------------- 1 | package validators 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | 7 | "github.com/markbates/validate" 8 | ) 9 | 10 | type StringsMatch struct { 11 | Name string 12 | Field string 13 | Field2 string 14 | Message string 15 | } 16 | 17 | // IsValid performs the validation equality of two strings. 18 | func (v *StringsMatch) IsValid(errors *validate.Errors) { 19 | if strings.TrimSpace(v.Field) != strings.TrimSpace(v.Field2) { 20 | if v.Message == "" { 21 | v.Message = fmt.Sprintf("%s does not equal %s.", v.Field, v.Field2) 22 | } 23 | errors.Add(GenerateKey(v.Name), v.Message) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /validators/strings_match_test.go: -------------------------------------------------------------------------------- 1 | package validators_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/markbates/validate" 7 | "github.com/markbates/validate/validators" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | func Test_StringsMatch_IsValid(t *testing.T) { 12 | r := require.New(t) 13 | var cases = []struct { 14 | str1 string 15 | str2 string 16 | expected bool 17 | }{ 18 | {"test", "test", true}, 19 | {"test_fail", "test_true", false}, 20 | {"test with space", " test with space ", true}, 21 | {" test with space second", " test with space second ", true}, 22 | } 23 | 24 | for _, test_case := range cases { 25 | v := validators.StringsMatch{Name: "strings", Field: test_case.str1, Field2: test_case.str2} 26 | errors := validate.NewErrors() 27 | v.IsValid(errors) 28 | r.Equal(test_case.expected, !errors.HasAny(), "Str1: %s, Str2: %s", test_case.str1, test_case.str2) 29 | } 30 | } 31 | 32 | func BenchmarkStringsMatch_IsValid_Valid(b *testing.B) { 33 | errors := validate.NewErrors() 34 | for i := 0; i <= b.N; i++ { 35 | v := validators.StringsMatch{Name: "strings", Field: " Some string ", Field2: " Some string "} 36 | v.IsValid(errors) 37 | } 38 | } 39 | 40 | func BenchmarkStringsMatch_IsValid_InValid(b *testing.B) { 41 | errors := validate.NewErrors() 42 | for i := 0; i <= b.N; i++ { 43 | v := validators.StringsMatch{Name: "strings", Field: " Some string ", Field2: " Some string failure"} 44 | v.IsValid(errors) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /validators/time_after_time.go: -------------------------------------------------------------------------------- 1 | package validators 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | 7 | "github.com/markbates/validate" 8 | ) 9 | 10 | type TimeAfterTime struct { 11 | FirstName string 12 | FirstTime time.Time 13 | SecondName string 14 | SecondTime time.Time 15 | } 16 | 17 | func (v *TimeAfterTime) IsValid(errors *validate.Errors) { 18 | if v.FirstTime.UnixNano() < v.SecondTime.UnixNano() { 19 | errors.Add(GenerateKey(v.FirstName), fmt.Sprintf("%s must be after %s.", v.FirstName, v.SecondName)) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /validators/time_after_time_test.go: -------------------------------------------------------------------------------- 1 | package validators_test 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | 7 | "github.com/markbates/validate" 8 | . "github.com/markbates/validate/validators" 9 | "github.com/stretchr/testify/require" 10 | ) 11 | 12 | func Test_TimeAfterTime(t *testing.T) { 13 | r := require.New(t) 14 | now := time.Now() 15 | v := TimeAfterTime{ 16 | FirstName: "Opens At", FirstTime: now.Add(100000), 17 | SecondName: "Now", SecondTime: now, 18 | } 19 | 20 | es := validate.NewErrors() 21 | v.IsValid(es) 22 | r.Equal(0, es.Count()) 23 | 24 | v.SecondTime = now.Add(200000) 25 | v.IsValid(es) 26 | 27 | r.Equal(1, es.Count()) 28 | r.Equal(es.Get("opens_at"), []string{"Opens At must be after Now."}) 29 | } 30 | -------------------------------------------------------------------------------- /validators/time_is_before_time.go: -------------------------------------------------------------------------------- 1 | package validators 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | 7 | "github.com/markbates/validate" 8 | ) 9 | 10 | type TimeIsBeforeTime struct { 11 | FirstName string 12 | FirstTime time.Time 13 | SecondName string 14 | SecondTime time.Time 15 | } 16 | 17 | func (v *TimeIsBeforeTime) IsValid(errors *validate.Errors) { 18 | if v.FirstTime.UnixNano() > v.SecondTime.UnixNano() { 19 | errors.Add(GenerateKey(v.FirstName), fmt.Sprintf("%s must be before %s.", v.FirstName, v.SecondName)) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /validators/time_is_before_time_test.go: -------------------------------------------------------------------------------- 1 | package validators_test 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | 7 | "github.com/markbates/validate" 8 | . "github.com/markbates/validate/validators" 9 | "github.com/stretchr/testify/require" 10 | ) 11 | 12 | func Test_TimeIsBeforeTime(t *testing.T) { 13 | r := require.New(t) 14 | now := time.Now() 15 | v := TimeIsBeforeTime{ 16 | FirstName: "Opens At", FirstTime: now, 17 | SecondName: "Closes At", SecondTime: now.Add(100000), 18 | } 19 | 20 | es := validate.NewErrors() 21 | v.IsValid(es) 22 | r.Equal(0, es.Count()) 23 | 24 | v.SecondTime = now.Add(-100000) 25 | v.IsValid(es) 26 | 27 | r.Equal(1, es.Count()) 28 | r.Equal(es.Get("opens_at"), []string{"Opens At must be before Closes At."}) 29 | } 30 | -------------------------------------------------------------------------------- /validators/time_is_present.go: -------------------------------------------------------------------------------- 1 | package validators 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | 7 | "github.com/markbates/validate" 8 | ) 9 | 10 | type TimeIsPresent struct { 11 | Name string 12 | Field time.Time 13 | } 14 | 15 | func (v *TimeIsPresent) IsValid(errors *validate.Errors) { 16 | t := time.Time{} 17 | if v.Field.UnixNano() == t.UnixNano() { 18 | errors.Add(GenerateKey(v.Name), fmt.Sprintf("%s can not be blank.", v.Name)) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /validators/time_is_present_test.go: -------------------------------------------------------------------------------- 1 | package validators_test 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | 7 | "github.com/markbates/validate" 8 | . "github.com/markbates/validate/validators" 9 | "github.com/stretchr/testify/require" 10 | ) 11 | 12 | func Test_TimeIsPresent(t *testing.T) { 13 | r := require.New(t) 14 | v := TimeIsPresent{"Created At", time.Now()} 15 | es := validate.NewErrors() 16 | v.IsValid(es) 17 | r.Equal(0, es.Count()) 18 | 19 | v = TimeIsPresent{"Created At", time.Time{}} 20 | v.IsValid(es) 21 | r.Equal(1, es.Count()) 22 | r.Equal(es.Get("created_at"), []string{"Created At can not be blank."}) 23 | } 24 | -------------------------------------------------------------------------------- /validators/url_is_present.go: -------------------------------------------------------------------------------- 1 | package validators 2 | 3 | import ( 4 | "fmt" 5 | "net/url" 6 | 7 | "github.com/markbates/validate" 8 | ) 9 | 10 | type URLIsPresent struct { 11 | Name string 12 | Field string 13 | Message string 14 | } 15 | 16 | // IsValid performs the validation to check if URL is formatted correctly 17 | // uses net/url ParseRequestURI to check validity 18 | func (v *URLIsPresent) IsValid(errors *validate.Errors) { 19 | if v.Field == "http://" || v.Field == "https://" { 20 | v.Message = fmt.Sprintf("%s url is empty", v.Name) 21 | errors.Add(GenerateKey(v.Name), v.Message) 22 | } 23 | parsedUrl, err := url.ParseRequestURI(v.Field) 24 | if err != nil { 25 | if v.Message == "" { 26 | v.Message = fmt.Sprintf("%s does not match url format. Err: %s", v.Name, 27 | err) 28 | } 29 | errors.Add(GenerateKey(v.Name), v.Message) 30 | } else { 31 | if parsedUrl.Scheme != "" && parsedUrl.Scheme != "http" && parsedUrl.Scheme != "https" { 32 | v.Message = fmt.Sprintf("%s invalid url scheme", v.Name) 33 | errors.Add(GenerateKey(v.Name), v.Message) 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /validators/url_is_present_test.go: -------------------------------------------------------------------------------- 1 | package validators 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/markbates/validate" 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func Test_URLIsPresent(t *testing.T) { 11 | r := require.New(t) 12 | 13 | var tests = []struct { 14 | url string 15 | valid bool 16 | }{ 17 | {"", false}, 18 | {"http://", false}, 19 | {"https://", false}, 20 | {"http", false}, 21 | {"google.com", false}, 22 | {"http://www.google.com", true}, 23 | {"http://google.com", true}, 24 | {"google.com", false}, 25 | {"https://www.google.cOM", true}, 26 | {"ht123tps://www.google.cOM", false}, 27 | {"https://golang.Org", true}, 28 | {"https://invalid#$%#$@.Org", false}, 29 | } 30 | for _, test := range tests { 31 | v := URLIsPresent{Name: "URL", Field: test.url} 32 | errors := validate.NewErrors() 33 | v.IsValid(errors) 34 | r.Equal(test.valid, !errors.HasAny(), test.url, errors.Error()) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /validators/uuid_is_present.go: -------------------------------------------------------------------------------- 1 | package validators 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | 7 | "github.com/markbates/validate" 8 | "github.com/satori/go.uuid" 9 | ) 10 | 11 | type UUIDIsPresent struct { 12 | Name string 13 | Field uuid.UUID 14 | } 15 | 16 | func (v *UUIDIsPresent) IsValid(errors *validate.Errors) { 17 | s := v.Field.String() 18 | if strings.TrimSpace(s) == "" || v.Field == uuid.Nil { 19 | errors.Add(GenerateKey(v.Name), fmt.Sprintf("%s can not be blank.", v.Name)) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /validators/uuid_is_present_test.go: -------------------------------------------------------------------------------- 1 | package validators_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/markbates/validate" 7 | . "github.com/markbates/validate/validators" 8 | uuid "github.com/satori/go.uuid" 9 | "github.com/stretchr/testify/require" 10 | ) 11 | 12 | func Test_UUIDIsPresent(t *testing.T) { 13 | r := require.New(t) 14 | 15 | id := uuid.NewV4() 16 | v := UUIDIsPresent{"Name", id} 17 | errors := validate.NewErrors() 18 | v.IsValid(errors) 19 | r.Equal(errors.Count(), 0) 20 | 21 | v = UUIDIsPresent{"Name", uuid.UUID{}} 22 | v.IsValid(errors) 23 | r.Equal(errors.Count(), 1) 24 | r.Equal(errors.Get("name"), []string{"Name can not be blank."}) 25 | } 26 | --------------------------------------------------------------------------------