pax_global_header00006660000000000000000000000064140211052360014504gustar00rootroot0000000000000052 comment=f21760c49a8d602d863493de796926d2a5c1138d govalidator-11.0.1/000077500000000000000000000000001402110523600140775ustar00rootroot00000000000000govalidator-11.0.1/.circleci/000077500000000000000000000000001402110523600157325ustar00rootroot00000000000000govalidator-11.0.1/.circleci/config.yml000066400000000000000000000004251402110523600177230ustar00rootroot00000000000000version: 2 jobs: build: docker: - image: circleci/golang:1.13 working_directory: /go/src/github.com/asaskevich/govalidator steps: - checkout - run: diff -u /dev/null <(gofmt -d .) - run: go get -v -t -d ./... - run: go test -v ./... govalidator-11.0.1/.github/000077500000000000000000000000001402110523600154375ustar00rootroot00000000000000govalidator-11.0.1/.github/ISSUE_TEMPLATE/000077500000000000000000000000001402110523600176225ustar00rootroot00000000000000govalidator-11.0.1/.github/ISSUE_TEMPLATE/BC_Break.md000077500000000000000000000015201402110523600215350ustar00rootroot00000000000000--- name: 💥 BC Break about: Have you encountered an issue during upgrade? 💣 --- ### BC Break Report | Q | A |------------ | ------ | Version | x.y.z #### Summary #### Previous behavior #### Current behavior #### How to reproduce govalidator-11.0.1/.github/ISSUE_TEMPLATE/Bug.md000077500000000000000000000012141402110523600206620ustar00rootroot00000000000000--- name: 🐞 Bug Report about: Something is broken? 🔨 --- ### Bug Report | Q | A |------------ | ------ | Version(s) | x.y.z #### Summary #### Current behavior #### How to reproduce #### Expected behavior govalidator-11.0.1/.github/ISSUE_TEMPLATE/Feature_Request.md000077500000000000000000000006221402110523600232520ustar00rootroot00000000000000--- name: 🎉 Feature Request about: You have an idea or feature that should be implemented? 🎩 --- ### Feature Request | Q | A |------------ | ------ | New Feature | yes | RFC | yes/no | BC Break | yes/no #### Summary govalidator-11.0.1/.github/ISSUE_TEMPLATE/config.yml000077500000000000000000000003221402110523600216120ustar00rootroot00000000000000blank_issues_enabled: false contact_links: - name: ❓ Support & Discussion url: https://gitter.im/asaskevich/govalidator about: 'You can leave comments and participate in the discussion via Gitter:' govalidator-11.0.1/.github/PULL_REQUEST_TEMPLATE.md000077500000000000000000000030531402110523600212440ustar00rootroot00000000000000 | Q | A |-------------- | ------ | Documentation | yes/no | Bugfix | yes/no | BC Break | yes/no | New Feature | yes/no | RFC | yes/no | QA | yes/no ### Description govalidator-11.0.1/.gitignore000066400000000000000000000003151402110523600160660ustar00rootroot00000000000000bin/ .idea/ # Binaries for programs and plugins *.exe *.exe~ *.dll *.so *.dylib # Test binary, built with `go test -c` *.test # Output of the go coverage tool, specifically when used with LiteIDE *.out govalidator-11.0.1/.travis.yml000066400000000000000000000003231402110523600162060ustar00rootroot00000000000000language: go dist: xenial go: - '1.10' - '1.11' - '1.12' - '1.13' - 'tip' script: - go test -coverpkg=./... -coverprofile=coverage.info -timeout=5s - bash <(curl -s https://codecov.io/bash) govalidator-11.0.1/CODE_OF_CONDUCT.md000077500000000000000000000044411402110523600167040ustar00rootroot00000000000000# Contributor Code of Conduct This project adheres to [The Code Manifesto](http://codemanifesto.com) as its guidelines for contributor interactions. ## The Code Manifesto We want to work in an ecosystem that empowers developers to reach their potential — one that encourages growth and effective collaboration. A space that is safe for all. A space such as this benefits everyone that participates in it. It encourages new developers to enter our field. It is through discussion and collaboration that we grow, and through growth that we improve. In the effort to create such a place, we hold to these values: 1. **Discrimination limits us.** This includes discrimination on the basis of race, gender, sexual orientation, gender identity, age, nationality, technology and any other arbitrary exclusion of a group of people. 2. **Boundaries honor us.** Your comfort levels are not everyone’s comfort levels. Remember that, and if brought to your attention, heed it. 3. **We are our biggest assets.** None of us were born masters of our trade. Each of us has been helped along the way. Return that favor, when and where you can. 4. **We are resources for the future.** As an extension of #3, share what you know. Make yourself a resource to help those that come after you. 5. **Respect defines us.** Treat others as you wish to be treated. Make your discussions, criticisms and debates from a position of respectfulness. Ask yourself, is it true? Is it necessary? Is it constructive? Anything less is unacceptable. 6. **Reactions require grace.** Angry responses are valid, but abusive language and vindictive actions are toxic. When something happens that offends you, handle it assertively, but be respectful. Escalate reasonably, and try to allow the offender an opportunity to explain themselves, and possibly correct the issue. 7. **Opinions are just that: opinions.** Each and every one of us, due to our background and upbringing, have varying opinions. That is perfectly acceptable. Remember this: if you respect your own opinions, you should respect the opinions of others. 8. **To err is human.** You might not intend it, but mistakes do happen and contribute to build experience. Tolerate honest mistakes, and don't hesitate to apologize if you make one yourself. govalidator-11.0.1/CONTRIBUTING.md000066400000000000000000000102521402110523600163300ustar00rootroot00000000000000#### Support If you do have a contribution to the package, feel free to create a Pull Request or an Issue. #### What to contribute If you don't know what to do, there are some features and functions that need to be done - [ ] Refactor code - [ ] Edit docs and [README](https://github.com/asaskevich/govalidator/README.md): spellcheck, grammar and typo check - [ ] Create actual list of contributors and projects that currently using this package - [ ] Resolve [issues and bugs](https://github.com/asaskevich/govalidator/issues) - [ ] Update actual [list of functions](https://github.com/asaskevich/govalidator#list-of-functions) - [ ] Update [list of validators](https://github.com/asaskevich/govalidator#validatestruct-2) that available for `ValidateStruct` and add new - [ ] Implement new validators: `IsFQDN`, `IsIMEI`, `IsPostalCode`, `IsISIN`, `IsISRC` etc - [x] Implement [validation by maps](https://github.com/asaskevich/govalidator/issues/224) - [ ] Implement fuzzing testing - [ ] Implement some struct/map/array utilities - [ ] Implement map/array validation - [ ] Implement benchmarking - [ ] Implement batch of examples - [ ] Look at forks for new features and fixes #### Advice Feel free to create what you want, but keep in mind when you implement new features: - Code must be clear and readable, names of variables/constants clearly describes what they are doing - Public functions must be documented and described in source file and added to README.md to the list of available functions - There are must be unit-tests for any new functions and improvements ## Financial contributions We also welcome financial contributions in full transparency on our [open collective](https://opencollective.com/govalidator). Anyone can file an expense. If the expense makes sense for the development of the community, it will be "merged" in the ledger of our open collective by the core contributors and the person who filed the expense will be reimbursed. ## Credits ### Contributors Thank you to all the people who have already contributed to govalidator! ### Backers Thank you to all our backers! [[Become a backer](https://opencollective.com/govalidator#backer)] ### Sponsors Thank you to all our sponsors! (please ask your company to also support this open source project by [becoming a sponsor](https://opencollective.com/govalidator#sponsor)) govalidator-11.0.1/LICENSE000066400000000000000000000020751402110523600151100ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2014-2020 Alex Saskevich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.govalidator-11.0.1/README.md000066400000000000000000000571021402110523600153630ustar00rootroot00000000000000govalidator =========== [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/asaskevich/govalidator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![GoDoc](https://godoc.org/github.com/asaskevich/govalidator?status.png)](https://godoc.org/github.com/asaskevich/govalidator) [![Build Status](https://travis-ci.org/asaskevich/govalidator.svg?branch=master)](https://travis-ci.org/asaskevich/govalidator) [![Coverage](https://codecov.io/gh/asaskevich/govalidator/branch/master/graph/badge.svg)](https://codecov.io/gh/asaskevich/govalidator) [![Go Report Card](https://goreportcard.com/badge/github.com/asaskevich/govalidator)](https://goreportcard.com/report/github.com/asaskevich/govalidator) [![GoSearch](http://go-search.org/badge?id=github.com%2Fasaskevich%2Fgovalidator)](http://go-search.org/view?id=github.com%2Fasaskevich%2Fgovalidator) [![Backers on Open Collective](https://opencollective.com/govalidator/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/govalidator/sponsors/badge.svg)](#sponsors) [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fasaskevich%2Fgovalidator.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fasaskevich%2Fgovalidator?ref=badge_shield) A package of validators and sanitizers for strings, structs and collections. Based on [validator.js](https://github.com/chriso/validator.js). #### Installation Make sure that Go is installed on your computer. Type the following command in your terminal: go get github.com/asaskevich/govalidator or you can get specified release of the package with `gopkg.in`: go get gopkg.in/asaskevich/govalidator.v10 After it the package is ready to use. #### Import package in your project Add following line in your `*.go` file: ```go import "github.com/asaskevich/govalidator" ``` If you are unhappy to use long `govalidator`, you can do something like this: ```go import ( valid "github.com/asaskevich/govalidator" ) ``` #### Activate behavior to require all fields have a validation tag by default `SetFieldsRequiredByDefault` causes validation to fail when struct fields do not include validations or are not explicitly marked as exempt (using `valid:"-"` or `valid:"email,optional"`). A good place to activate this is a package init function or the main() function. `SetNilPtrAllowedByRequired` causes validation to pass when struct fields marked by `required` are set to nil. This is disabled by default for consistency, but some packages that need to be able to determine between `nil` and `zero value` state can use this. If disabled, both `nil` and `zero` values cause validation errors. ```go import "github.com/asaskevich/govalidator" func init() { govalidator.SetFieldsRequiredByDefault(true) } ``` Here's some code to explain it: ```go // this struct definition will fail govalidator.ValidateStruct() (and the field values do not matter): type exampleStruct struct { Name string `` Email string `valid:"email"` } // this, however, will only fail when Email is empty or an invalid email address: type exampleStruct2 struct { Name string `valid:"-"` Email string `valid:"email"` } // lastly, this will only fail when Email is an invalid email address but not when it's empty: type exampleStruct2 struct { Name string `valid:"-"` Email string `valid:"email,optional"` } ``` #### Recent breaking changes (see [#123](https://github.com/asaskevich/govalidator/pull/123)) ##### Custom validator function signature A context was added as the second parameter, for structs this is the object being validated – this makes dependent validation possible. ```go import "github.com/asaskevich/govalidator" // old signature func(i interface{}) bool // new signature func(i interface{}, o interface{}) bool ``` ##### Adding a custom validator This was changed to prevent data races when accessing custom validators. ```go import "github.com/asaskevich/govalidator" // before govalidator.CustomTypeTagMap["customByteArrayValidator"] = func(i interface{}, o interface{}) bool { // ... } // after govalidator.CustomTypeTagMap.Set("customByteArrayValidator", func(i interface{}, o interface{}) bool { // ... }) ``` #### List of functions: ```go func Abs(value float64) float64 func BlackList(str, chars string) string func ByteLength(str string, params ...string) bool func CamelCaseToUnderscore(str string) string func Contains(str, substring string) bool func Count(array []interface{}, iterator ConditionIterator) int func Each(array []interface{}, iterator Iterator) func ErrorByField(e error, field string) string func ErrorsByField(e error) map[string]string func Filter(array []interface{}, iterator ConditionIterator) []interface{} func Find(array []interface{}, iterator ConditionIterator) interface{} func GetLine(s string, index int) (string, error) func GetLines(s string) []string func HasLowerCase(str string) bool func HasUpperCase(str string) bool func HasWhitespace(str string) bool func HasWhitespaceOnly(str string) bool func InRange(value interface{}, left interface{}, right interface{}) bool func InRangeFloat32(value, left, right float32) bool func InRangeFloat64(value, left, right float64) bool func InRangeInt(value, left, right interface{}) bool func IsASCII(str string) bool func IsAlpha(str string) bool func IsAlphanumeric(str string) bool func IsBase64(str string) bool func IsByteLength(str string, min, max int) bool func IsCIDR(str string) bool func IsCRC32(str string) bool func IsCRC32b(str string) bool func IsCreditCard(str string) bool func IsDNSName(str string) bool func IsDataURI(str string) bool func IsDialString(str string) bool func IsDivisibleBy(str, num string) bool func IsEmail(str string) bool func IsExistingEmail(email string) bool func IsFilePath(str string) (bool, int) func IsFloat(str string) bool func IsFullWidth(str string) bool func IsHalfWidth(str string) bool func IsHash(str string, algorithm string) bool func IsHexadecimal(str string) bool func IsHexcolor(str string) bool func IsHost(str string) bool func IsIP(str string) bool func IsIPv4(str string) bool func IsIPv6(str string) bool func IsISBN(str string, version int) bool func IsISBN10(str string) bool func IsISBN13(str string) bool func IsISO3166Alpha2(str string) bool func IsISO3166Alpha3(str string) bool func IsISO4217(str string) bool func IsISO693Alpha2(str string) bool func IsISO693Alpha3b(str string) bool func IsIn(str string, params ...string) bool func IsInRaw(str string, params ...string) bool func IsInt(str string) bool func IsJSON(str string) bool func IsLatitude(str string) bool func IsLongitude(str string) bool func IsLowerCase(str string) bool func IsMAC(str string) bool func IsMD4(str string) bool func IsMD5(str string) bool func IsMagnetURI(str string) bool func IsMongoID(str string) bool func IsMultibyte(str string) bool func IsNatural(value float64) bool func IsNegative(value float64) bool func IsNonNegative(value float64) bool func IsNonPositive(value float64) bool func IsNotNull(str string) bool func IsNull(str string) bool func IsNumeric(str string) bool func IsPort(str string) bool func IsPositive(value float64) bool func IsPrintableASCII(str string) bool func IsRFC3339(str string) bool func IsRFC3339WithoutZone(str string) bool func IsRGBcolor(str string) bool func IsRegex(str string) bool func IsRequestURI(rawurl string) bool func IsRequestURL(rawurl string) bool func IsRipeMD128(str string) bool func IsRipeMD160(str string) bool func IsRsaPub(str string, params ...string) bool func IsRsaPublicKey(str string, keylen int) bool func IsSHA1(str string) bool func IsSHA256(str string) bool func IsSHA384(str string) bool func IsSHA512(str string) bool func IsSSN(str string) bool func IsSemver(str string) bool func IsTiger128(str string) bool func IsTiger160(str string) bool func IsTiger192(str string) bool func IsTime(str string, format string) bool func IsType(v interface{}, params ...string) bool func IsURL(str string) bool func IsUTFDigit(str string) bool func IsUTFLetter(str string) bool func IsUTFLetterNumeric(str string) bool func IsUTFNumeric(str string) bool func IsUUID(str string) bool func IsUUIDv3(str string) bool func IsUUIDv4(str string) bool func IsUUIDv5(str string) bool func IsULID(str string) bool func IsUnixTime(str string) bool func IsUpperCase(str string) bool func IsVariableWidth(str string) bool func IsWhole(value float64) bool func LeftTrim(str, chars string) string func Map(array []interface{}, iterator ResultIterator) []interface{} func Matches(str, pattern string) bool func MaxStringLength(str string, params ...string) bool func MinStringLength(str string, params ...string) bool func NormalizeEmail(str string) (string, error) func PadBoth(str string, padStr string, padLen int) string func PadLeft(str string, padStr string, padLen int) string func PadRight(str string, padStr string, padLen int) string func PrependPathToErrors(err error, path string) error func Range(str string, params ...string) bool func RemoveTags(s string) string func ReplacePattern(str, pattern, replace string) string func Reverse(s string) string func RightTrim(str, chars string) string func RuneLength(str string, params ...string) bool func SafeFileName(str string) string func SetFieldsRequiredByDefault(value bool) func SetNilPtrAllowedByRequired(value bool) func Sign(value float64) float64 func StringLength(str string, params ...string) bool func StringMatches(s string, params ...string) bool func StripLow(str string, keepNewLines bool) string func ToBoolean(str string) (bool, error) func ToFloat(str string) (float64, error) func ToInt(value interface{}) (res int64, err error) func ToJSON(obj interface{}) (string, error) func ToString(obj interface{}) string func Trim(str, chars string) string func Truncate(str string, length int, ending string) string func TruncatingErrorf(str string, args ...interface{}) error func UnderscoreToCamelCase(s string) string func ValidateMap(inputMap map[string]interface{}, validationMap map[string]interface{}) (bool, error) func ValidateStruct(s interface{}) (bool, error) func WhiteList(str, chars string) string type ConditionIterator type CustomTypeValidator type Error func (e Error) Error() string type Errors func (es Errors) Error() string func (es Errors) Errors() []error type ISO3166Entry type ISO693Entry type InterfaceParamValidator type Iterator type ParamValidator type ResultIterator type UnsupportedTypeError func (e *UnsupportedTypeError) Error() string type Validator ``` #### Examples ###### IsURL ```go println(govalidator.IsURL(`http://user@pass:domain.com/path/page`)) ``` ###### IsType ```go println(govalidator.IsType("Bob", "string")) println(govalidator.IsType(1, "int")) i := 1 println(govalidator.IsType(&i, "*int")) ``` IsType can be used through the tag `type` which is essential for map validation: ```go type User struct { Name string `valid:"type(string)"` Age int `valid:"type(int)"` Meta interface{} `valid:"type(string)"` } result, err := govalidator.ValidateStruct(User{"Bob", 20, "meta"}) if err != nil { println("error: " + err.Error()) } println(result) ``` ###### ToString ```go type User struct { FirstName string LastName string } str := govalidator.ToString(&User{"John", "Juan"}) println(str) ``` ###### Each, Map, Filter, Count for slices Each iterates over the slice/array and calls Iterator for every item ```go data := []interface{}{1, 2, 3, 4, 5} var fn govalidator.Iterator = func(value interface{}, index int) { println(value.(int)) } govalidator.Each(data, fn) ``` ```go data := []interface{}{1, 2, 3, 4, 5} var fn govalidator.ResultIterator = func(value interface{}, index int) interface{} { return value.(int) * 3 } _ = govalidator.Map(data, fn) // result = []interface{}{1, 6, 9, 12, 15} ``` ```go data := []interface{}{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} var fn govalidator.ConditionIterator = func(value interface{}, index int) bool { return value.(int)%2 == 0 } _ = govalidator.Filter(data, fn) // result = []interface{}{2, 4, 6, 8, 10} _ = govalidator.Count(data, fn) // result = 5 ``` ###### ValidateStruct [#2](https://github.com/asaskevich/govalidator/pull/2) If you want to validate structs, you can use tag `valid` for any field in your structure. All validators used with this field in one tag are separated by comma. If you want to skip validation, place `-` in your tag. If you need a validator that is not on the list below, you can add it like this: ```go govalidator.TagMap["duck"] = govalidator.Validator(func(str string) bool { return str == "duck" }) ``` For completely custom validators (interface-based), see below. Here is a list of available validators for struct fields (validator - used function): ```go "email": IsEmail, "url": IsURL, "dialstring": IsDialString, "requrl": IsRequestURL, "requri": IsRequestURI, "alpha": IsAlpha, "utfletter": IsUTFLetter, "alphanum": IsAlphanumeric, "utfletternum": IsUTFLetterNumeric, "numeric": IsNumeric, "utfnumeric": IsUTFNumeric, "utfdigit": IsUTFDigit, "hexadecimal": IsHexadecimal, "hexcolor": IsHexcolor, "rgbcolor": IsRGBcolor, "lowercase": IsLowerCase, "uppercase": IsUpperCase, "int": IsInt, "float": IsFloat, "null": IsNull, "uuid": IsUUID, "uuidv3": IsUUIDv3, "uuidv4": IsUUIDv4, "uuidv5": IsUUIDv5, "creditcard": IsCreditCard, "isbn10": IsISBN10, "isbn13": IsISBN13, "json": IsJSON, "multibyte": IsMultibyte, "ascii": IsASCII, "printableascii": IsPrintableASCII, "fullwidth": IsFullWidth, "halfwidth": IsHalfWidth, "variablewidth": IsVariableWidth, "base64": IsBase64, "datauri": IsDataURI, "ip": IsIP, "port": IsPort, "ipv4": IsIPv4, "ipv6": IsIPv6, "dns": IsDNSName, "host": IsHost, "mac": IsMAC, "latitude": IsLatitude, "longitude": IsLongitude, "ssn": IsSSN, "semver": IsSemver, "rfc3339": IsRFC3339, "rfc3339WithoutZone": IsRFC3339WithoutZone, "ISO3166Alpha2": IsISO3166Alpha2, "ISO3166Alpha3": IsISO3166Alpha3, "ulid": IsULID, ``` Validators with parameters ```go "range(min|max)": Range, "length(min|max)": ByteLength, "runelength(min|max)": RuneLength, "stringlength(min|max)": StringLength, "matches(pattern)": StringMatches, "in(string1|string2|...|stringN)": IsIn, "rsapub(keylength)" : IsRsaPub, "minstringlength(int): MinStringLength, "maxstringlength(int): MaxStringLength, ``` Validators with parameters for any type ```go "type(type)": IsType, ``` And here is small example of usage: ```go type Post struct { Title string `valid:"alphanum,required"` Message string `valid:"duck,ascii"` Message2 string `valid:"animal(dog)"` AuthorIP string `valid:"ipv4"` Date string `valid:"-"` } post := &Post{ Title: "My Example Post", Message: "duck", Message2: "dog", AuthorIP: "123.234.54.3", } // Add your own struct validation tags govalidator.TagMap["duck"] = govalidator.Validator(func(str string) bool { return str == "duck" }) // Add your own struct validation tags with parameter govalidator.ParamTagMap["animal"] = govalidator.ParamValidator(func(str string, params ...string) bool { species := params[0] return str == species }) govalidator.ParamTagRegexMap["animal"] = regexp.MustCompile("^animal\\((\\w+)\\)$") result, err := govalidator.ValidateStruct(post) if err != nil { println("error: " + err.Error()) } println(result) ``` ###### ValidateMap [#2](https://github.com/asaskevich/govalidator/pull/338) If you want to validate maps, you can use the map to be validated and a validation map that contain the same tags used in ValidateStruct, both maps have to be in the form `map[string]interface{}` So here is small example of usage: ```go var mapTemplate = map[string]interface{}{ "name":"required,alpha", "family":"required,alpha", "email":"required,email", "cell-phone":"numeric", "address":map[string]interface{}{ "line1":"required,alphanum", "line2":"alphanum", "postal-code":"numeric", }, } var inputMap = map[string]interface{}{ "name":"Bob", "family":"Smith", "email":"foo@bar.baz", "address":map[string]interface{}{ "line1":"", "line2":"", "postal-code":"", }, } result, err := govalidator.ValidateMap(inputMap, mapTemplate) if err != nil { println("error: " + err.Error()) } println(result) ``` ###### WhiteList ```go // Remove all characters from string ignoring characters between "a" and "z" println(govalidator.WhiteList("a3a43a5a4a3a2a23a4a5a4a3a4", "a-z") == "aaaaaaaaaaaa") ``` ###### Custom validation functions Custom validation using your own domain specific validators is also available - here's an example of how to use it: ```go import "github.com/asaskevich/govalidator" type CustomByteArray [6]byte // custom types are supported and can be validated type StructWithCustomByteArray struct { ID CustomByteArray `valid:"customByteArrayValidator,customMinLengthValidator"` // multiple custom validators are possible as well and will be evaluated in sequence Email string `valid:"email"` CustomMinLength int `valid:"-"` } govalidator.CustomTypeTagMap.Set("customByteArrayValidator", func(i interface{}, context interface{}) bool { switch v := context.(type) { // you can type switch on the context interface being validated case StructWithCustomByteArray: // you can check and validate against some other field in the context, // return early or not validate against the context at all – your choice case SomeOtherType: // ... default: // expecting some other type? Throw/panic here or continue } switch v := i.(type) { // type switch on the struct field being validated case CustomByteArray: for _, e := range v { // this validator checks that the byte array is not empty, i.e. not all zeroes if e != 0 { return true } } } return false }) govalidator.CustomTypeTagMap.Set("customMinLengthValidator", func(i interface{}, context interface{}) bool { switch v := context.(type) { // this validates a field against the value in another field, i.e. dependent validation case StructWithCustomByteArray: return len(v.ID) >= v.CustomMinLength } return false }) ``` ###### Loop over Error() By default .Error() returns all errors in a single String. To access each error you can do this: ```go if err != nil { errs := err.(govalidator.Errors).Errors() for _, e := range errs { fmt.Println(e.Error()) } } ``` ###### Custom error messages Custom error messages are supported via annotations by adding the `~` separator - here's an example of how to use it: ```go type Ticket struct { Id int64 `json:"id"` FirstName string `json:"firstname" valid:"required~First name is blank"` } ``` #### Notes Documentation is available here: [godoc.org](https://godoc.org/github.com/asaskevich/govalidator). Full information about code coverage is also available here: [govalidator on gocover.io](http://gocover.io/github.com/asaskevich/govalidator). #### Support If you do have a contribution to the package, feel free to create a Pull Request or an Issue. #### What to contribute If you don't know what to do, there are some features and functions that need to be done - [ ] Refactor code - [ ] Edit docs and [README](https://github.com/asaskevich/govalidator/README.md): spellcheck, grammar and typo check - [ ] Create actual list of contributors and projects that currently using this package - [ ] Resolve [issues and bugs](https://github.com/asaskevich/govalidator/issues) - [ ] Update actual [list of functions](https://github.com/asaskevich/govalidator#list-of-functions) - [ ] Update [list of validators](https://github.com/asaskevich/govalidator#validatestruct-2) that available for `ValidateStruct` and add new - [ ] Implement new validators: `IsFQDN`, `IsIMEI`, `IsPostalCode`, `IsISIN`, `IsISRC` etc - [x] Implement [validation by maps](https://github.com/asaskevich/govalidator/issues/224) - [ ] Implement fuzzing testing - [ ] Implement some struct/map/array utilities - [ ] Implement map/array validation - [ ] Implement benchmarking - [ ] Implement batch of examples - [ ] Look at forks for new features and fixes #### Advice Feel free to create what you want, but keep in mind when you implement new features: - Code must be clear and readable, names of variables/constants clearly describes what they are doing - Public functions must be documented and described in source file and added to README.md to the list of available functions - There are must be unit-tests for any new functions and improvements ## Credits ### Contributors This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)]. #### Special thanks to [contributors](https://github.com/asaskevich/govalidator/graphs/contributors) * [Daniel Lohse](https://github.com/annismckenzie) * [Attila Oláh](https://github.com/attilaolah) * [Daniel Korner](https://github.com/Dadie) * [Steven Wilkin](https://github.com/stevenwilkin) * [Deiwin Sarjas](https://github.com/deiwin) * [Noah Shibley](https://github.com/slugmobile) * [Nathan Davies](https://github.com/nathj07) * [Matt Sanford](https://github.com/mzsanford) * [Simon ccl1115](https://github.com/ccl1115) ### Backers Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/govalidator#backer)] ### Sponsors Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/govalidator#sponsor)] ## License [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fasaskevich%2Fgovalidator.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fasaskevich%2Fgovalidator?ref=badge_large) govalidator-11.0.1/arrays.go000066400000000000000000000055171402110523600157370ustar00rootroot00000000000000package govalidator // Iterator is the function that accepts element of slice/array and its index type Iterator func(interface{}, int) // ResultIterator is the function that accepts element of slice/array and its index and returns any result type ResultIterator func(interface{}, int) interface{} // ConditionIterator is the function that accepts element of slice/array and its index and returns boolean type ConditionIterator func(interface{}, int) bool // ReduceIterator is the function that accepts two element of slice/array and returns result of merging those values type ReduceIterator func(interface{}, interface{}) interface{} // Some validates that any item of array corresponds to ConditionIterator. Returns boolean. func Some(array []interface{}, iterator ConditionIterator) bool { res := false for index, data := range array { res = res || iterator(data, index) } return res } // Every validates that every item of array corresponds to ConditionIterator. Returns boolean. func Every(array []interface{}, iterator ConditionIterator) bool { res := true for index, data := range array { res = res && iterator(data, index) } return res } // Reduce boils down a list of values into a single value by ReduceIterator func Reduce(array []interface{}, iterator ReduceIterator, initialValue interface{}) interface{} { for _, data := range array { initialValue = iterator(initialValue, data) } return initialValue } // Each iterates over the slice and apply Iterator to every item func Each(array []interface{}, iterator Iterator) { for index, data := range array { iterator(data, index) } } // Map iterates over the slice and apply ResultIterator to every item. Returns new slice as a result. func Map(array []interface{}, iterator ResultIterator) []interface{} { var result = make([]interface{}, len(array)) for index, data := range array { result[index] = iterator(data, index) } return result } // Find iterates over the slice and apply ConditionIterator to every item. Returns first item that meet ConditionIterator or nil otherwise. func Find(array []interface{}, iterator ConditionIterator) interface{} { for index, data := range array { if iterator(data, index) { return data } } return nil } // Filter iterates over the slice and apply ConditionIterator to every item. Returns new slice. func Filter(array []interface{}, iterator ConditionIterator) []interface{} { var result = make([]interface{}, 0) for index, data := range array { if iterator(data, index) { result = append(result, data) } } return result } // Count iterates over the slice and apply ConditionIterator to every item. Returns count of items that meets ConditionIterator. func Count(array []interface{}, iterator ConditionIterator) int { count := 0 for index, data := range array { if iterator(data, index) { count = count + 1 } } return count } govalidator-11.0.1/arrays_benchmark_test.go000066400000000000000000000030641402110523600210030ustar00rootroot00000000000000package govalidator // Benchmark testing is produced with randomly filled array of 1 million elements import ( "math/rand" "testing" ) func randomInt(min, max int) int { return min + rand.Intn(max-min) } func randomArray(n int) (res []interface{}) { res = make([]interface{}, n) for i := 0; i < n; i++ { res[i] = randomInt(-1000, 1000) } return } func BenchmarkEach(b *testing.B) { data := randomArray(1000000) b.ResetTimer() for n := 0; n < b.N; n++ { acc := 0 var fn Iterator = func(value interface{}, index int) { acc = acc + value.(int) } Each(data, fn) } } func BenchmarkMap(b *testing.B) { data := randomArray(1000000) b.ResetTimer() for n := 0; n < b.N; n++ { var fn ResultIterator = func(value interface{}, index int) interface{} { return value.(int) * 3 } _ = Map(data, fn) } } func BenchmarkFind(b *testing.B) { data := randomArray(1000000) b.ResetTimer() for n := 0; n < b.N; n++ { findElement := 96 var fn1 ConditionIterator = func(value interface{}, index int) bool { return value.(int) == findElement } _ = Find(data, fn1) } } func BenchmarkFilter(b *testing.B) { data := randomArray(1000000) b.ResetTimer() for n := 0; n < b.N; n++ { var fn ConditionIterator = func(value interface{}, index int) bool { return value.(int)%2 == 0 } _ = Filter(data, fn) } } func BenchmarkCount(b *testing.B) { data := randomArray(1000000) b.ResetTimer() for n := 0; n < b.N; n++ { var fn ConditionIterator = func(value interface{}, index int) bool { return value.(int)%2 == 0 } _ = Count(data, fn) } } govalidator-11.0.1/arrays_example_test.go000066400000000000000000000020441402110523600205010ustar00rootroot00000000000000package govalidator func ExampleFilter() { data := []interface{}{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} var fn ConditionIterator = func(value interface{}, index int) bool { return value.(int)%2 == 0 } _ = Filter(data, fn) // result = []interface{}{2, 4, 6, 8, 10} } func ExampleCount() { data := []interface{}{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} var fn ConditionIterator = func(value interface{}, index int) bool { return value.(int)%2 == 0 } _ = Count(data, fn) // result = 5 } func ExampleMap() { data := []interface{}{1, 2, 3, 4, 5} var fn ResultIterator = func(value interface{}, index int) interface{} { return value.(int) * 3 } _ = Map(data, fn) // result = []interface{}{1, 6, 9, 12, 15} } func ExampleEach() { data := []interface{}{1, 2, 3, 4, 5} var fn Iterator = func(value interface{}, index int) { println(value.(int)) } Each(data, fn) } func ExampleFind() { data := []interface{}{1, 2, 3, 4, 5} var fn ConditionIterator = func(value interface{}, index int) bool { return value.(int) == 4 } _ = Find(data, fn) // result = 4 } govalidator-11.0.1/arrays_test.go000066400000000000000000000040731402110523600167720ustar00rootroot00000000000000package govalidator import "testing" func TestEach(t *testing.T) { // TODO Maybe refactor? t.Parallel() acc := 0 data := []interface{}{1, 2, 3, 4, 5} var fn Iterator = func(value interface{}, index int) { acc = acc + value.(int) } Each(data, fn) if acc != 15 { t.Errorf("Expected Each(..) to be %v, got %v", 15, acc) } } func TestMap(t *testing.T) { // TODO Maybe refactor? t.Parallel() data := []interface{}{1, 2, 3, 4, 5} var fn ResultIterator = func(value interface{}, index int) interface{} { return value.(int) * 3 } result := Map(data, fn) for i, d := range result { if d != fn(data[i], i) { t.Errorf("Expected Map(..) to be %v, got %v", fn(data[i], i), d) } } } func TestFind(t *testing.T) { // TODO Maybe refactor? t.Parallel() findElement := 96 data := []interface{}{1, 2, 3, 4, findElement, 5} var fn1 ConditionIterator = func(value interface{}, index int) bool { return value.(int) == findElement } var fn2 ConditionIterator = func(value interface{}, index int) bool { value, _ = value.(string) return value == "govalidator" } val1 := Find(data, fn1) val2 := Find(data, fn2) if val1 != findElement { t.Errorf("Expected Find(..) to be %v, got %v", findElement, val1) } if val2 != nil { t.Errorf("Expected Find(..) to be %v, got %v", nil, val2) } } func TestFilter(t *testing.T) { // TODO Maybe refactor? t.Parallel() data := []interface{}{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} answer := []interface{}{2, 4, 6, 8, 10} var fn ConditionIterator = func(value interface{}, index int) bool { return value.(int)%2 == 0 } result := Filter(data, fn) for i := range result { if result[i] != answer[i] { t.Errorf("Expected Filter(..) to be %v, got %v", answer[i], result[i]) } } } func TestCount(t *testing.T) { // TODO Maybe refactor? t.Parallel() data := []interface{}{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} count := 5 var fn ConditionIterator = func(value interface{}, index int) bool { return value.(int)%2 == 0 } result := Count(data, fn) if result != count { t.Errorf("Expected Count(..) to be %v, got %v", count, result) } } govalidator-11.0.1/converter.go000066400000000000000000000034271402110523600164430ustar00rootroot00000000000000package govalidator import ( "encoding/json" "fmt" "reflect" "strconv" ) // ToString convert the input to a string. func ToString(obj interface{}) string { res := fmt.Sprintf("%v", obj) return res } // ToJSON convert the input to a valid JSON string func ToJSON(obj interface{}) (string, error) { res, err := json.Marshal(obj) if err != nil { res = []byte("") } return string(res), err } // ToFloat convert the input string to a float, or 0.0 if the input is not a float. func ToFloat(value interface{}) (res float64, err error) { val := reflect.ValueOf(value) switch value.(type) { case int, int8, int16, int32, int64: res = float64(val.Int()) case uint, uint8, uint16, uint32, uint64: res = float64(val.Uint()) case float32, float64: res = val.Float() case string: res, err = strconv.ParseFloat(val.String(), 64) if err != nil { res = 0 } default: err = fmt.Errorf("ToInt: unknown interface type %T", value) res = 0 } return } // ToInt convert the input string or any int type to an integer type 64, or 0 if the input is not an integer. func ToInt(value interface{}) (res int64, err error) { val := reflect.ValueOf(value) switch value.(type) { case int, int8, int16, int32, int64: res = val.Int() case uint, uint8, uint16, uint32, uint64: res = int64(val.Uint()) case float32, float64: res = int64(val.Float()) case string: if IsInt(val.String()) { res, err = strconv.ParseInt(val.String(), 0, 64) if err != nil { res = 0 } } else { err = fmt.Errorf("ToInt: invalid numeric format %g", value) res = 0 } default: err = fmt.Errorf("ToInt: unknown interface type %T", value) res = 0 } return } // ToBoolean convert the input string to a boolean. func ToBoolean(str string) (bool, error) { return strconv.ParseBool(str) } govalidator-11.0.1/converter_benchmark_test.go000066400000000000000000000012231402110523600215040ustar00rootroot00000000000000package govalidator import ( "testing" ) func BenchmarkToBoolean(b *testing.B) { b.ResetTimer() for n := 0; n < b.N; n++ { _, _ = ToBoolean("False ") } } func BenchmarkToInt(b *testing.B) { b.ResetTimer() for n := 0; n < b.N; n++ { _, _ = ToInt("-22342342.2342") } } func BenchmarkToFloat(b *testing.B) { b.ResetTimer() for n := 0; n < b.N; n++ { _, _ = ToFloat("-22342342.2342") } } func BenchmarkToString(b *testing.B) { b.ResetTimer() for n := 0; n < b.N; n++ { ToString(randomArray(1000000)) } } func BenchmarkToJson(b *testing.B) { b.ResetTimer() for n := 0; n < b.N; n++ { _, _ = ToJSON(randomArray(1000000)) } } govalidator-11.0.1/converter_example_test.go000066400000000000000000000017131402110523600212110ustar00rootroot00000000000000package govalidator import "time" func ExampleToBoolean() { // Returns the boolean value represented by the string. // It accepts 1, t, T, TRUE, true, True, 0, f, F, FALSE, false, False. // Any other value returns an error. _, _ = ToBoolean("false") // false, nil _, _ = ToBoolean("T") // true, nil _, _ = ToBoolean("123123") // false, error } func ExampleToInt() { _, _ = ToInt(1.0) // 1, nil _, _ = ToInt("-124") // -124, nil _, _ = ToInt("false") // 0, error } func ExampleToFloat() { _, _ = ToFloat("-124.2e123") // -124.2e123, nil _, _ = ToFloat("false") // 0, error } func ExampleToString() { _ = ToString(new(interface{})) // 0xc000090200 _ = ToString(time.Second + time.Hour) // 1h1s _ = ToString(123) // 123 } func ExampleToJSON() { _, _ = ToJSON([]int{1, 2, 3}) // [1, 2, 3] _, _ = ToJSON(map[int]int{1: 2, 2: 3}) // { "1": 2, "2": 3 } _, _ = ToJSON(func() {}) // error } govalidator-11.0.1/converter_test.go000066400000000000000000000045161402110523600175020ustar00rootroot00000000000000package govalidator import ( "fmt" "testing" ) func TestToInt(t *testing.T) { tests := []interface{}{"1000", "-123", "abcdef", "100000000000000000000000000000000000000000000", false} expected := []int64{1000, -123, 0, 0, 0} for i := 0; i < len(tests); i++ { result, _ := ToInt(tests[i]) if result != expected[i] { t.Log("Case ", i, ": expected ", expected[i], " when result is ", result) t.FailNow() } } } func TestToBoolean(t *testing.T) { tests := []string{"true", "1", "True", "false", "0", "abcdef"} expected := []bool{true, true, true, false, false, false} for i := 0; i < len(tests); i++ { res, _ := ToBoolean(tests[i]) if res != expected[i] { t.Log("Case ", i, ": expected ", expected[i], " when result is ", res) t.FailNow() } } } func toString(t *testing.T, test interface{}, expected string) { res := ToString(test) if res != expected { t.Log("Case ToString: expected ", expected, " when result is ", res) t.FailNow() } } func TestToString(t *testing.T) { toString(t, "str123", "str123") toString(t, 123, "123") toString(t, 12.3, "12.3") toString(t, true, "true") toString(t, 1.5+10i, "(1.5+10i)") // Sprintf function not guarantee that maps with equal keys always will be equal in string representation //toString(t, struct{ Keys map[int]int }{Keys: map[int]int{1: 2, 3: 4}}, "{map[1:2 3:4]}") } func TestToFloat(t *testing.T) { tests := []string{"", "123", "-.01", "10.", "string", "1.23e3", ".23e10"} expected := []float64{0, 123, -0.01, 10.0, 0, 1230, 0.23e10} for i := 0; i < len(tests); i++ { res, _ := ToFloat(tests[i]) if res != expected[i] { t.Log("Case ", i, ": expected ", expected[i], " when result is ", res) t.FailNow() } } } func TestToJSON(t *testing.T) { tests := []interface{}{"test", map[string]string{"a": "b", "b": "c"}, func() error { return fmt.Errorf("Error") }} expected := [][]string{ {"\"test\"", ""}, {"{\"a\":\"b\",\"b\":\"c\"}", ""}, {"", "json: unsupported type: func() error"}, } for i, test := range tests { actual, err := ToJSON(test) if actual != expected[i][0] { t.Errorf("Expected toJSON(%v) to return '%v', got '%v'", test, expected[i][0], actual) } if fmt.Sprintf("%v", err) != expected[i][1] { t.Errorf("Expected error returned from toJSON(%v) to return '%v', got '%v'", test, expected[i][1], fmt.Sprintf("%v", err)) } } } govalidator-11.0.1/doc.go000066400000000000000000000001501402110523600151670ustar00rootroot00000000000000package govalidator // A package of validators and sanitizers for strings, structures and collections. govalidator-11.0.1/error.go000066400000000000000000000016511402110523600155620ustar00rootroot00000000000000package govalidator import ( "sort" "strings" ) // Errors is an array of multiple errors and conforms to the error interface. type Errors []error // Errors returns itself. func (es Errors) Errors() []error { return es } func (es Errors) Error() string { var errs []string for _, e := range es { errs = append(errs, e.Error()) } sort.Strings(errs) return strings.Join(errs, ";") } // Error encapsulates a name, an error and whether there's a custom error message or not. type Error struct { Name string Err error CustomErrorMessageExists bool // Validator indicates the name of the validator that failed Validator string Path []string } func (e Error) Error() string { if e.CustomErrorMessageExists { return e.Err.Error() } errName := e.Name if len(e.Path) > 0 { errName = strings.Join(append(e.Path, e.Name), ".") } return errName + ": " + e.Err.Error() } govalidator-11.0.1/error_test.go000066400000000000000000000016171402110523600166230ustar00rootroot00000000000000package govalidator import ( "fmt" "testing" ) func TestErrorsToString(t *testing.T) { t.Parallel() customErr := &Error{Name: "Custom Error Name", Err: fmt.Errorf("stdlib error")} customErrWithCustomErrorMessage := &Error{Name: "Custom Error Name 2", Err: fmt.Errorf("Bad stuff happened"), CustomErrorMessageExists: true} var tests = []struct { param1 Errors expected string }{ {Errors{}, ""}, {Errors{fmt.Errorf("Error 1")}, "Error 1"}, {Errors{fmt.Errorf("Error 1"), fmt.Errorf("Error 2")}, "Error 1;Error 2"}, {Errors{customErr, fmt.Errorf("Error 2")}, "Custom Error Name: stdlib error;Error 2"}, {Errors{fmt.Errorf("Error 123"), customErrWithCustomErrorMessage}, "Bad stuff happened;Error 123"}, } for _, test := range tests { actual := test.param1.Error() if actual != test.expected { t.Errorf("Expected Error() to return '%v', got '%v'", test.expected, actual) } } } govalidator-11.0.1/go.mod000066400000000000000000000000621402110523600152030ustar00rootroot00000000000000module github.com/asaskevich/govalidator go 1.13 govalidator-11.0.1/numerics.go000066400000000000000000000050501402110523600162530ustar00rootroot00000000000000package govalidator import ( "math" ) // Abs returns absolute value of number func Abs(value float64) float64 { return math.Abs(value) } // Sign returns signum of number: 1 in case of value > 0, -1 in case of value < 0, 0 otherwise func Sign(value float64) float64 { if value > 0 { return 1 } else if value < 0 { return -1 } else { return 0 } } // IsNegative returns true if value < 0 func IsNegative(value float64) bool { return value < 0 } // IsPositive returns true if value > 0 func IsPositive(value float64) bool { return value > 0 } // IsNonNegative returns true if value >= 0 func IsNonNegative(value float64) bool { return value >= 0 } // IsNonPositive returns true if value <= 0 func IsNonPositive(value float64) bool { return value <= 0 } // InRangeInt returns true if value lies between left and right border func InRangeInt(value, left, right interface{}) bool { value64, _ := ToInt(value) left64, _ := ToInt(left) right64, _ := ToInt(right) if left64 > right64 { left64, right64 = right64, left64 } return value64 >= left64 && value64 <= right64 } // InRangeFloat32 returns true if value lies between left and right border func InRangeFloat32(value, left, right float32) bool { if left > right { left, right = right, left } return value >= left && value <= right } // InRangeFloat64 returns true if value lies between left and right border func InRangeFloat64(value, left, right float64) bool { if left > right { left, right = right, left } return value >= left && value <= right } // InRange returns true if value lies between left and right border, generic type to handle int, float32, float64 and string. // All types must the same type. // False if value doesn't lie in range or if it incompatible or not comparable func InRange(value interface{}, left interface{}, right interface{}) bool { switch value.(type) { case int: intValue, _ := ToInt(value) intLeft, _ := ToInt(left) intRight, _ := ToInt(right) return InRangeInt(intValue, intLeft, intRight) case float32, float64: intValue, _ := ToFloat(value) intLeft, _ := ToFloat(left) intRight, _ := ToFloat(right) return InRangeFloat64(intValue, intLeft, intRight) case string: return value.(string) >= left.(string) && value.(string) <= right.(string) default: return false } } // IsWhole returns true if value is whole number func IsWhole(value float64) bool { return math.Remainder(value, 1) == 0 } // IsNatural returns true if value is natural number (positive and whole) func IsNatural(value float64) bool { return IsWhole(value) && IsPositive(value) } govalidator-11.0.1/numerics_benchmark_test.go000066400000000000000000000027041402110523600213270ustar00rootroot00000000000000package govalidator import "testing" func BenchmarkAbs(b *testing.B) { b.ResetTimer() for n := 0; n < b.N; n++ { _ = Abs(-123.3e1) } } func BenchmarkSign(b *testing.B) { b.ResetTimer() for n := 0; n < b.N; n++ { _ = Sign(-123.3e1) } } func BenchmarkIsNegative(b *testing.B) { b.ResetTimer() for n := 0; n < b.N; n++ { _ = IsNegative(-123.3e1) } } func BenchmarkIsPositive(b *testing.B) { b.ResetTimer() for n := 0; n < b.N; n++ { _ = IsPositive(-123.3e1) } } func BenchmarkIsNonNegative(b *testing.B) { b.ResetTimer() for n := 0; n < b.N; n++ { _ = IsNonNegative(-123.3e1) } } func BenchmarkIsNonPositive(b *testing.B) { b.ResetTimer() for n := 0; n < b.N; n++ { _ = IsNonPositive(-123.3e1) } } func BenchmarkInRangeInt(b *testing.B) { b.ResetTimer() for n := 0; n < b.N; n++ { _ = InRangeInt(10, -100, 100) } } func BenchmarkInRangeFloat32(b *testing.B) { b.ResetTimer() for n := 0; n < b.N; n++ { _ = InRangeFloat32(10, -100, 100) } } func BenchmarkInRangeFloat64(b *testing.B) { b.ResetTimer() for n := 0; n < b.N; n++ { _ = InRangeFloat64(10, -100, 100) } } func BenchmarkInRange(b *testing.B) { b.ResetTimer() for n := 0; n < b.N; n++ { _ = InRange("abc", "a", "cba") } } func BenchmarkIsWhole(b *testing.B) { b.ResetTimer() for n := 0; n < b.N; n++ { _ = IsWhole(123.132) } } func BenchmarkIsNatural(b *testing.B) { b.ResetTimer() for n := 0; n < b.N; n++ { _ = IsNatural(123.132) } } govalidator-11.0.1/numerics_example_test.go000066400000000000000000000031511402110523600210250ustar00rootroot00000000000000package govalidator func ExampleAbs() { _ = Abs(-123.3e1) // 123.3e1 _ = Abs(+0) // 0 _ = Abs(321) // 321 } func ExampleSign() { _ = Sign(-123) // -1 _ = Sign(123) // 1 _ = Sign(0) // 0 } func ExampleIsNegative() { _ = IsNegative(-123) // true _ = IsNegative(0) // false _ = IsNegative(123) // false } func ExampleIsPositive() { _ = IsPositive(-123) // false _ = IsPositive(0) // false _ = IsPositive(123) // true } func ExampleIsNonNegative() { _ = IsNonNegative(-123) // false _ = IsNonNegative(0) // true _ = IsNonNegative(123) // true } func ExampleIsNonPositive() { _ = IsNonPositive(-123) // true _ = IsNonPositive(0) // true _ = IsNonPositive(123) // false } func ExampleInRangeInt() { _ = InRangeInt(10, -10, 10) // true _ = InRangeInt(10, 10, 20) // true _ = InRangeInt(10, 11, 20) // false } func ExampleInRangeFloat32() { _ = InRangeFloat32(10.02, -10.124, 10.234) // true _ = InRangeFloat32(10.123, 10.123, 20.431) // true _ = InRangeFloat32(10.235, 11.124, 20.235) // false } func ExampleInRangeFloat64() { _ = InRangeFloat64(10.02, -10.124, 10.234) // true _ = InRangeFloat64(10.123, 10.123, 20.431) // true _ = InRangeFloat64(10.235, 11.124, 20.235) // false } func ExampleInRange() { _ = InRange(10, 11, 20) // false _ = InRange(10.02, -10.124, 10.234) // true _ = InRange("abc", "a", "cba") // true } func ExampleIsWhole() { _ = IsWhole(1.123) // false _ = IsWhole(1.0) // true _ = IsWhole(10) // true } func ExampleIsNatural() { _ = IsNatural(1.123) // false _ = IsNatural(1.0) // true _ = IsNatural(-10) // false } govalidator-11.0.1/numerics_test.go000066400000000000000000000275261402110523600173260ustar00rootroot00000000000000package govalidator import "testing" func TestAbs(t *testing.T) { t.Parallel() var tests = []struct { param float64 expected float64 }{ {0, 0}, {-1, 1}, {10, 10}, {3.14, 3.14}, {-96, 96}, {-10e-12, 10e-12}, } for _, test := range tests { actual := Abs(test.param) if actual != test.expected { t.Errorf("Expected Abs(%v) to be %v, got %v", test.param, test.expected, actual) } } } func TestSign(t *testing.T) { t.Parallel() var tests = []struct { param float64 expected float64 }{ {0, 0}, {-1, -1}, {10, 1}, {3.14, 1}, {-96, -1}, {-10e-12, -1}, } for _, test := range tests { actual := Sign(test.param) if actual != test.expected { t.Errorf("Expected Sign(%v) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsNegative(t *testing.T) { t.Parallel() var tests = []struct { param float64 expected bool }{ {0, false}, {-1, true}, {10, false}, {3.14, false}, {-96, true}, {-10e-12, true}, } for _, test := range tests { actual := IsNegative(test.param) if actual != test.expected { t.Errorf("Expected IsNegative(%v) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsNonNegative(t *testing.T) { t.Parallel() var tests = []struct { param float64 expected bool }{ {0, true}, {-1, false}, {10, true}, {3.14, true}, {-96, false}, {-10e-12, false}, } for _, test := range tests { actual := IsNonNegative(test.param) if actual != test.expected { t.Errorf("Expected IsNonNegative(%v) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsPositive(t *testing.T) { t.Parallel() var tests = []struct { param float64 expected bool }{ {0, false}, {-1, false}, {10, true}, {3.14, true}, {-96, false}, {-10e-12, false}, } for _, test := range tests { actual := IsPositive(test.param) if actual != test.expected { t.Errorf("Expected IsPositive(%v) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsNonPositive(t *testing.T) { t.Parallel() var tests = []struct { param float64 expected bool }{ {0, true}, {-1, true}, {10, false}, {3.14, false}, {-96, true}, {-10e-12, true}, } for _, test := range tests { actual := IsNonPositive(test.param) if actual != test.expected { t.Errorf("Expected IsNonPositive(%v) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsWhole(t *testing.T) { t.Parallel() var tests = []struct { param float64 expected bool }{ {0, true}, {-1, true}, {10, true}, {3.14, false}, {-96, true}, {-10e-12, false}, } for _, test := range tests { actual := IsWhole(test.param) if actual != test.expected { t.Errorf("Expected IsWhole(%v) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsNatural(t *testing.T) { t.Parallel() var tests = []struct { param float64 expected bool }{ {0, false}, {-1, false}, {10, true}, {3.14, false}, {96, true}, {-10e-12, false}, } for _, test := range tests { actual := IsNatural(test.param) if actual != test.expected { t.Errorf("Expected IsNatural(%v) to be %v, got %v", test.param, test.expected, actual) } } } func TestInRangeInt(t *testing.T) { t.Parallel() var testAsInts = []struct { param int left int right int expected bool }{ {0, 0, 0, true}, {1, 0, 0, false}, {-1, 0, 0, false}, {0, -1, 1, true}, {0, 0, 1, true}, {0, -1, 0, true}, {0, 0, -1, true}, {0, 10, 5, false}, } for _, test := range testAsInts { actual := InRangeInt(test.param, test.left, test.right) if actual != test.expected { t.Errorf("Expected InRangeInt(%v, %v, %v) to be %v, got %v using type int", test.param, test.left, test.right, test.expected, actual) } } var testAsInt8s = []struct { param int8 left int8 right int8 expected bool }{ {0, 0, 0, true}, {1, 0, 0, false}, {-1, 0, 0, false}, {0, -1, 1, true}, {0, 0, 1, true}, {0, -1, 0, true}, {0, 0, -1, true}, {0, 10, 5, false}, } for _, test := range testAsInt8s { actual := InRangeInt(test.param, test.left, test.right) if actual != test.expected { t.Errorf("Expected InRangeInt(%v, %v, %v) to be %v, got %v using type int8", test.param, test.left, test.right, test.expected, actual) } } var testAsInt16s = []struct { param int16 left int16 right int16 expected bool }{ {0, 0, 0, true}, {1, 0, 0, false}, {-1, 0, 0, false}, {0, -1, 1, true}, {0, 0, 1, true}, {0, -1, 0, true}, {0, 0, -1, true}, {0, 10, 5, false}, } for _, test := range testAsInt16s { actual := InRangeInt(test.param, test.left, test.right) if actual != test.expected { t.Errorf("Expected InRangeInt(%v, %v, %v) to be %v, got %v using type int16", test.param, test.left, test.right, test.expected, actual) } } var testAsInt32s = []struct { param int32 left int32 right int32 expected bool }{ {0, 0, 0, true}, {1, 0, 0, false}, {-1, 0, 0, false}, {0, -1, 1, true}, {0, 0, 1, true}, {0, -1, 0, true}, {0, 0, -1, true}, {0, 10, 5, false}, } for _, test := range testAsInt32s { actual := InRangeInt(test.param, test.left, test.right) if actual != test.expected { t.Errorf("Expected InRangeInt(%v, %v, %v) to be %v, got %v using type int32", test.param, test.left, test.right, test.expected, actual) } } var testAsInt64s = []struct { param int64 left int64 right int64 expected bool }{ {0, 0, 0, true}, {1, 0, 0, false}, {-1, 0, 0, false}, {0, -1, 1, true}, {0, 0, 1, true}, {0, -1, 0, true}, {0, 0, -1, true}, {0, 10, 5, false}, } for _, test := range testAsInt64s { actual := InRangeInt(test.param, test.left, test.right) if actual != test.expected { t.Errorf("Expected InRangeInt(%v, %v, %v) to be %v, got %v using type int64", test.param, test.left, test.right, test.expected, actual) } } var testAsUInts = []struct { param uint left uint right uint expected bool }{ {0, 0, 0, true}, {1, 0, 0, false}, {0, 0, 1, true}, {0, 10, 5, false}, } for _, test := range testAsUInts { actual := InRangeInt(test.param, test.left, test.right) if actual != test.expected { t.Errorf("Expected InRangeInt(%v, %v, %v) to be %v, got %v using type uint", test.param, test.left, test.right, test.expected, actual) } } var testAsUInt8s = []struct { param uint8 left uint8 right uint8 expected bool }{ {0, 0, 0, true}, {1, 0, 0, false}, {0, 0, 1, true}, {0, 10, 5, false}, } for _, test := range testAsUInt8s { actual := InRangeInt(test.param, test.left, test.right) if actual != test.expected { t.Errorf("Expected InRangeInt(%v, %v, %v) to be %v, got %v using type uint", test.param, test.left, test.right, test.expected, actual) } } var testAsUInt16s = []struct { param uint16 left uint16 right uint16 expected bool }{ {0, 0, 0, true}, {1, 0, 0, false}, {0, 0, 1, true}, {0, 10, 5, false}, } for _, test := range testAsUInt16s { actual := InRangeInt(test.param, test.left, test.right) if actual != test.expected { t.Errorf("Expected InRangeInt(%v, %v, %v) to be %v, got %v using type uint", test.param, test.left, test.right, test.expected, actual) } } var testAsUInt32s = []struct { param uint32 left uint32 right uint32 expected bool }{ {0, 0, 0, true}, {1, 0, 0, false}, {0, 0, 1, true}, {0, 10, 5, false}, } for _, test := range testAsUInt32s { actual := InRangeInt(test.param, test.left, test.right) if actual != test.expected { t.Errorf("Expected InRangeInt(%v, %v, %v) to be %v, got %v using type uint", test.param, test.left, test.right, test.expected, actual) } } var testAsUInt64s = []struct { param uint64 left uint64 right uint64 expected bool }{ {0, 0, 0, true}, {1, 0, 0, false}, {0, 0, 1, true}, {0, 10, 5, false}, } for _, test := range testAsUInt64s { actual := InRangeInt(test.param, test.left, test.right) if actual != test.expected { t.Errorf("Expected InRangeInt(%v, %v, %v) to be %v, got %v using type uint", test.param, test.left, test.right, test.expected, actual) } } var testAsStrings = []struct { param string left string right string expected bool }{ {"0", "0", "0", true}, {"1", "0", "0", false}, {"-1", "0", "0", false}, {"0", "-1", "1", true}, {"0", "0", "1", true}, {"0", "-1", "0", true}, {"0", "0", "-1", true}, {"0", "10", "5", false}, } for _, test := range testAsStrings { actual := InRangeInt(test.param, test.left, test.right) if actual != test.expected { t.Errorf("Expected InRangeInt(%v, %v, %v) to be %v, got %v using type string", test.param, test.left, test.right, test.expected, actual) } } } func TestInRangeFloat32(t *testing.T) { t.Parallel() var tests = []struct { param float32 left float32 right float32 expected bool }{ {0, 0, 0, true}, {1, 0, 0, false}, {-1, 0, 0, false}, {0, -1, 1, true}, {0, 0, 1, true}, {0, -1, 0, true}, {0, 0, -1, true}, {0, 10, 5, false}, } for _, test := range tests { actual := InRangeFloat32(test.param, test.left, test.right) if actual != test.expected { t.Errorf("Expected InRangeFloat32(%v, %v, %v) to be %v, got %v", test.param, test.left, test.right, test.expected, actual) } } } func TestInRangeFloat64(t *testing.T) { t.Parallel() var tests = []struct { param float64 left float64 right float64 expected bool }{ {0, 0, 0, true}, {1, 0, 0, false}, {-1, 0, 0, false}, {0, -1, 1, true}, {0, 0, 1, true}, {0, -1, 0, true}, {0, 0, -1, true}, {0, 10, 5, false}, } for _, test := range tests { actual := InRangeFloat64(test.param, test.left, test.right) if actual != test.expected { t.Errorf("Expected InRangeFloat64(%v, %v, %v) to be %v, got %v", test.param, test.left, test.right, test.expected, actual) } } } func TestInRange(t *testing.T) { t.Parallel() var testsInt = []struct { param int left int right int expected bool }{ {0, 0, 0, true}, {1, 0, 0, false}, {-1, 0, 0, false}, {0, -1, 1, true}, {0, 0, 1, true}, {0, -1, 0, true}, {0, 0, -1, true}, {0, 10, 5, false}, } for _, test := range testsInt { actual := InRange(test.param, test.left, test.right) if actual != test.expected { t.Errorf("Expected InRange(%v, %v, %v) to be %v, got %v", test.param, test.left, test.right, test.expected, actual) } } var testsFloat32 = []struct { param float32 left float32 right float32 expected bool }{ {0, 0, 0, true}, {1, 0, 0, false}, {-1, 0, 0, false}, {0, -1, 1, true}, {0, 0, 1, true}, {0, -1, 0, true}, {0, 0, -1, true}, {0, 10, 5, false}, } for _, test := range testsFloat32 { actual := InRange(test.param, test.left, test.right) if actual != test.expected { t.Errorf("Expected InRange(%v, %v, %v) to be %v, got %v", test.param, test.left, test.right, test.expected, actual) } } var testsFloat64 = []struct { param float64 left float64 right float64 expected bool }{ {0, 0, 0, true}, {1, 0, 0, false}, {-1, 0, 0, false}, {0, -1, 1, true}, {0, 0, 1, true}, {0, -1, 0, true}, {0, 0, -1, true}, {0, 10, 5, false}, } for _, test := range testsFloat64 { actual := InRange(test.param, test.left, test.right) if actual != test.expected { t.Errorf("Expected InRange(%v, %v, %v) to be %v, got %v", test.param, test.left, test.right, test.expected, actual) } } var testsTypeMix = []struct { param int left float64 right float64 expected bool }{ {0, 0, 0, true}, {1, 0, 0, false}, {-1, 0, 0, false}, {0, -1, 1, true}, {0, 0, 1, true}, {0, -1, 0, true}, {0, 0, -1, true}, {0, 10, 5, false}, } for _, test := range testsTypeMix { actual := InRange(test.param, test.left, test.right) if actual != test.expected { t.Errorf("Expected InRange(%v, %v, %v) to be %v, got %v", test.param, test.left, test.right, test.expected, actual) } } } govalidator-11.0.1/patterns.go000066400000000000000000000204641402110523600162740ustar00rootroot00000000000000package govalidator import "regexp" // Basic regular expressions for validating strings const ( Email string = "^(((([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}])))\\.?$" CreditCard string = "^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|(222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720)[0-9]{12}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\d{3})\\d{11}|6[27][0-9]{14})$" ISBN10 string = "^(?:[0-9]{9}X|[0-9]{10})$" ISBN13 string = "^(?:[0-9]{13})$" UUID3 string = "^[0-9a-f]{8}-[0-9a-f]{4}-3[0-9a-f]{3}-[0-9a-f]{4}-[0-9a-f]{12}$" UUID4 string = "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" UUID5 string = "^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" UUID string = "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$" Alpha string = "^[a-zA-Z]+$" Alphanumeric string = "^[a-zA-Z0-9]+$" Numeric string = "^[0-9]+$" Int string = "^(?:[-+]?(?:0|[1-9][0-9]*))$" Float string = "^(?:[-+]?(?:[0-9]+))?(?:\\.[0-9]*)?(?:[eE][\\+\\-]?(?:[0-9]+))?$" Hexadecimal string = "^[0-9a-fA-F]+$" Hexcolor string = "^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$" RGBcolor string = "^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*\\)$" ASCII string = "^[\x00-\x7F]+$" Multibyte string = "[^\x00-\x7F]" FullWidth string = "[^\u0020-\u007E\uFF61-\uFF9F\uFFA0-\uFFDC\uFFE8-\uFFEE0-9a-zA-Z]" HalfWidth string = "[\u0020-\u007E\uFF61-\uFF9F\uFFA0-\uFFDC\uFFE8-\uFFEE0-9a-zA-Z]" Base64 string = "^(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+\\/]{3}=|[A-Za-z0-9+\\/]{4})$" PrintableASCII string = "^[\x20-\x7E]+$" DataURI string = "^data:.+\\/(.+);base64$" MagnetURI string = "^magnet:\\?xt=urn:[a-zA-Z0-9]+:[a-zA-Z0-9]{32,40}&dn=.+&tr=.+$" Latitude string = "^[-+]?([1-8]?\\d(\\.\\d+)?|90(\\.0+)?)$" Longitude string = "^[-+]?(180(\\.0+)?|((1[0-7]\\d)|([1-9]?\\d))(\\.\\d+)?)$" DNSName string = `^([a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62}){1}(\.[a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62})*[\._]?$` IP string = `(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))` URLSchema string = `((ftp|tcp|udp|wss?|https?):\/\/)` URLUsername string = `(\S+(:\S*)?@)` URLPath string = `((\/|\?|#)[^\s]*)` URLPort string = `(:(\d{1,5}))` URLIP string = `([1-9]\d?|1\d\d|2[01]\d|22[0-3]|24\d|25[0-5])(\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])){2}(?:\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-5]))` URLSubdomain string = `((www\.)|([a-zA-Z0-9]+([-_\.]?[a-zA-Z0-9])*[a-zA-Z0-9]\.[a-zA-Z0-9]+))` URL = `^` + URLSchema + `?` + URLUsername + `?` + `((` + URLIP + `|(\[` + IP + `\])|(([a-zA-Z0-9]([a-zA-Z0-9-_]+)?[a-zA-Z0-9]([-\.][a-zA-Z0-9]+)*)|(` + URLSubdomain + `?))?(([a-zA-Z\x{00a1}-\x{ffff}0-9]+-?-?)*[a-zA-Z\x{00a1}-\x{ffff}0-9]+)(?:\.([a-zA-Z\x{00a1}-\x{ffff}]{1,}))?))\.?` + URLPort + `?` + URLPath + `?$` SSN string = `^\d{3}[- ]?\d{2}[- ]?\d{4}$` WinPath string = `^[a-zA-Z]:\\(?:[^\\/:*?"<>|\r\n]+\\)*[^\\/:*?"<>|\r\n]*$` UnixPath string = `^(/[^/\x00]*)+/?$` WinARPath string = `^(?:(?:[a-zA-Z]:|\\\\[a-z0-9_.$●-]+\\[a-z0-9_.$●-]+)\\|\\?[^\\/:*?"<>|\r\n]+\\?)(?:[^\\/:*?"<>|\r\n]+\\)*[^\\/:*?"<>|\r\n]*$` UnixARPath string = `^((\.{0,2}/)?([^/\x00]*))+/?$` Semver string = "^v?(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)(-(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(\\.(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*)?(\\+[0-9a-zA-Z-]+(\\.[0-9a-zA-Z-]+)*)?$" tagName string = "valid" hasLowerCase string = ".*[[:lower:]]" hasUpperCase string = ".*[[:upper:]]" hasWhitespace string = ".*[[:space:]]" hasWhitespaceOnly string = "^[[:space:]]+$" IMEI string = "^[0-9a-f]{14}$|^\\d{15}$|^\\d{18}$" IMSI string = "^\\d{14,15}$" E164 string = `^\+?[1-9]\d{1,14}$` ) // Used by IsFilePath func const ( // Unknown is unresolved OS type Unknown = iota // Win is Windows type Win // Unix is *nix OS types Unix ) var ( userRegexp = regexp.MustCompile("^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~.-]+$") hostRegexp = regexp.MustCompile("^[^\\s]+\\.[^\\s]+$") userDotRegexp = regexp.MustCompile("(^[.]{1})|([.]{1}$)|([.]{2,})") rxEmail = regexp.MustCompile(Email) rxCreditCard = regexp.MustCompile(CreditCard) rxISBN10 = regexp.MustCompile(ISBN10) rxISBN13 = regexp.MustCompile(ISBN13) rxUUID3 = regexp.MustCompile(UUID3) rxUUID4 = regexp.MustCompile(UUID4) rxUUID5 = regexp.MustCompile(UUID5) rxUUID = regexp.MustCompile(UUID) rxAlpha = regexp.MustCompile(Alpha) rxAlphanumeric = regexp.MustCompile(Alphanumeric) rxNumeric = regexp.MustCompile(Numeric) rxInt = regexp.MustCompile(Int) rxFloat = regexp.MustCompile(Float) rxHexadecimal = regexp.MustCompile(Hexadecimal) rxHexcolor = regexp.MustCompile(Hexcolor) rxRGBcolor = regexp.MustCompile(RGBcolor) rxASCII = regexp.MustCompile(ASCII) rxPrintableASCII = regexp.MustCompile(PrintableASCII) rxMultibyte = regexp.MustCompile(Multibyte) rxFullWidth = regexp.MustCompile(FullWidth) rxHalfWidth = regexp.MustCompile(HalfWidth) rxBase64 = regexp.MustCompile(Base64) rxDataURI = regexp.MustCompile(DataURI) rxMagnetURI = regexp.MustCompile(MagnetURI) rxLatitude = regexp.MustCompile(Latitude) rxLongitude = regexp.MustCompile(Longitude) rxDNSName = regexp.MustCompile(DNSName) rxURL = regexp.MustCompile(URL) rxSSN = regexp.MustCompile(SSN) rxWinPath = regexp.MustCompile(WinPath) rxUnixPath = regexp.MustCompile(UnixPath) rxARWinPath = regexp.MustCompile(WinARPath) rxARUnixPath = regexp.MustCompile(UnixARPath) rxSemver = regexp.MustCompile(Semver) rxHasLowerCase = regexp.MustCompile(hasLowerCase) rxHasUpperCase = regexp.MustCompile(hasUpperCase) rxHasWhitespace = regexp.MustCompile(hasWhitespace) rxHasWhitespaceOnly = regexp.MustCompile(hasWhitespaceOnly) rxIMEI = regexp.MustCompile(IMEI) rxIMSI = regexp.MustCompile(IMSI) rxE164 = regexp.MustCompile(E164) ) govalidator-11.0.1/types.go000066400000000000000000001030051402110523600155710ustar00rootroot00000000000000package govalidator import ( "reflect" "regexp" "sort" "sync" ) // Validator is a wrapper for a validator function that returns bool and accepts string. type Validator func(str string) bool // CustomTypeValidator is a wrapper for validator functions that returns bool and accepts any type. // The second parameter should be the context (in the case of validating a struct: the whole object being validated). type CustomTypeValidator func(i interface{}, o interface{}) bool // ParamValidator is a wrapper for validator functions that accept additional parameters. type ParamValidator func(str string, params ...string) bool // InterfaceParamValidator is a wrapper for functions that accept variants parameters for an interface value type InterfaceParamValidator func(in interface{}, params ...string) bool type tagOptionsMap map[string]tagOption func (t tagOptionsMap) orderedKeys() []string { var keys []string for k := range t { keys = append(keys, k) } sort.Slice(keys, func(a, b int) bool { return t[keys[a]].order < t[keys[b]].order }) return keys } type tagOption struct { name string customErrorMessage string order int } // UnsupportedTypeError is a wrapper for reflect.Type type UnsupportedTypeError struct { Type reflect.Type } // stringValues is a slice of reflect.Value holding *reflect.StringValue. // It implements the methods to sort by string. type stringValues []reflect.Value // InterfaceParamTagMap is a map of functions accept variants parameters for an interface value var InterfaceParamTagMap = map[string]InterfaceParamValidator{ "type": IsType, } // InterfaceParamTagRegexMap maps interface param tags to their respective regexes. var InterfaceParamTagRegexMap = map[string]*regexp.Regexp{ "type": regexp.MustCompile(`^type\((.*)\)$`), } // ParamTagMap is a map of functions accept variants parameters var ParamTagMap = map[string]ParamValidator{ "length": ByteLength, "range": Range, "runelength": RuneLength, "stringlength": StringLength, "matches": StringMatches, "in": IsInRaw, "rsapub": IsRsaPub, "minstringlength": MinStringLength, "maxstringlength": MaxStringLength, } // ParamTagRegexMap maps param tags to their respective regexes. var ParamTagRegexMap = map[string]*regexp.Regexp{ "range": regexp.MustCompile("^range\\((\\d+)\\|(\\d+)\\)$"), "length": regexp.MustCompile("^length\\((\\d+)\\|(\\d+)\\)$"), "runelength": regexp.MustCompile("^runelength\\((\\d+)\\|(\\d+)\\)$"), "stringlength": regexp.MustCompile("^stringlength\\((\\d+)\\|(\\d+)\\)$"), "in": regexp.MustCompile(`^in\((.*)\)`), "matches": regexp.MustCompile(`^matches\((.+)\)$`), "rsapub": regexp.MustCompile("^rsapub\\((\\d+)\\)$"), "minstringlength": regexp.MustCompile("^minstringlength\\((\\d+)\\)$"), "maxstringlength": regexp.MustCompile("^maxstringlength\\((\\d+)\\)$"), } type customTypeTagMap struct { validators map[string]CustomTypeValidator sync.RWMutex } func (tm *customTypeTagMap) Get(name string) (CustomTypeValidator, bool) { tm.RLock() defer tm.RUnlock() v, ok := tm.validators[name] return v, ok } func (tm *customTypeTagMap) Set(name string, ctv CustomTypeValidator) { tm.Lock() defer tm.Unlock() tm.validators[name] = ctv } // CustomTypeTagMap is a map of functions that can be used as tags for ValidateStruct function. // Use this to validate compound or custom types that need to be handled as a whole, e.g. // `type UUID [16]byte` (this would be handled as an array of bytes). var CustomTypeTagMap = &customTypeTagMap{validators: make(map[string]CustomTypeValidator)} // TagMap is a map of functions, that can be used as tags for ValidateStruct function. var TagMap = map[string]Validator{ "email": IsEmail, "url": IsURL, "dialstring": IsDialString, "requrl": IsRequestURL, "requri": IsRequestURI, "alpha": IsAlpha, "utfletter": IsUTFLetter, "alphanum": IsAlphanumeric, "utfletternum": IsUTFLetterNumeric, "numeric": IsNumeric, "utfnumeric": IsUTFNumeric, "utfdigit": IsUTFDigit, "hexadecimal": IsHexadecimal, "hexcolor": IsHexcolor, "rgbcolor": IsRGBcolor, "lowercase": IsLowerCase, "uppercase": IsUpperCase, "int": IsInt, "float": IsFloat, "null": IsNull, "notnull": IsNotNull, "uuid": IsUUID, "uuidv3": IsUUIDv3, "uuidv4": IsUUIDv4, "uuidv5": IsUUIDv5, "creditcard": IsCreditCard, "isbn10": IsISBN10, "isbn13": IsISBN13, "json": IsJSON, "multibyte": IsMultibyte, "ascii": IsASCII, "printableascii": IsPrintableASCII, "fullwidth": IsFullWidth, "halfwidth": IsHalfWidth, "variablewidth": IsVariableWidth, "base64": IsBase64, "datauri": IsDataURI, "ip": IsIP, "port": IsPort, "ipv4": IsIPv4, "ipv6": IsIPv6, "dns": IsDNSName, "host": IsHost, "mac": IsMAC, "latitude": IsLatitude, "longitude": IsLongitude, "ssn": IsSSN, "semver": IsSemver, "rfc3339": IsRFC3339, "rfc3339WithoutZone": IsRFC3339WithoutZone, "ISO3166Alpha2": IsISO3166Alpha2, "ISO3166Alpha3": IsISO3166Alpha3, "ISO4217": IsISO4217, "IMEI": IsIMEI, "ulid": IsULID, } // ISO3166Entry stores country codes type ISO3166Entry struct { EnglishShortName string FrenchShortName string Alpha2Code string Alpha3Code string Numeric string } //ISO3166List based on https://www.iso.org/obp/ui/#search/code/ Code Type "Officially Assigned Codes" var ISO3166List = []ISO3166Entry{ {"Afghanistan", "Afghanistan (l')", "AF", "AFG", "004"}, {"Albania", "Albanie (l')", "AL", "ALB", "008"}, {"Antarctica", "Antarctique (l')", "AQ", "ATA", "010"}, {"Algeria", "Algérie (l')", "DZ", "DZA", "012"}, {"American Samoa", "Samoa américaines (les)", "AS", "ASM", "016"}, {"Andorra", "Andorre (l')", "AD", "AND", "020"}, {"Angola", "Angola (l')", "AO", "AGO", "024"}, {"Antigua and Barbuda", "Antigua-et-Barbuda", "AG", "ATG", "028"}, {"Azerbaijan", "Azerbaïdjan (l')", "AZ", "AZE", "031"}, {"Argentina", "Argentine (l')", "AR", "ARG", "032"}, {"Australia", "Australie (l')", "AU", "AUS", "036"}, {"Austria", "Autriche (l')", "AT", "AUT", "040"}, {"Bahamas (the)", "Bahamas (les)", "BS", "BHS", "044"}, {"Bahrain", "Bahreïn", "BH", "BHR", "048"}, {"Bangladesh", "Bangladesh (le)", "BD", "BGD", "050"}, {"Armenia", "Arménie (l')", "AM", "ARM", "051"}, {"Barbados", "Barbade (la)", "BB", "BRB", "052"}, {"Belgium", "Belgique (la)", "BE", "BEL", "056"}, {"Bermuda", "Bermudes (les)", "BM", "BMU", "060"}, {"Bhutan", "Bhoutan (le)", "BT", "BTN", "064"}, {"Bolivia (Plurinational State of)", "Bolivie (État plurinational de)", "BO", "BOL", "068"}, {"Bosnia and Herzegovina", "Bosnie-Herzégovine (la)", "BA", "BIH", "070"}, {"Botswana", "Botswana (le)", "BW", "BWA", "072"}, {"Bouvet Island", "Bouvet (l'Île)", "BV", "BVT", "074"}, {"Brazil", "Brésil (le)", "BR", "BRA", "076"}, {"Belize", "Belize (le)", "BZ", "BLZ", "084"}, {"British Indian Ocean Territory (the)", "Indien (le Territoire britannique de l'océan)", "IO", "IOT", "086"}, {"Solomon Islands", "Salomon (Îles)", "SB", "SLB", "090"}, {"Virgin Islands (British)", "Vierges britanniques (les Îles)", "VG", "VGB", "092"}, {"Brunei Darussalam", "Brunéi Darussalam (le)", "BN", "BRN", "096"}, {"Bulgaria", "Bulgarie (la)", "BG", "BGR", "100"}, {"Myanmar", "Myanmar (le)", "MM", "MMR", "104"}, {"Burundi", "Burundi (le)", "BI", "BDI", "108"}, {"Belarus", "Bélarus (le)", "BY", "BLR", "112"}, {"Cambodia", "Cambodge (le)", "KH", "KHM", "116"}, {"Cameroon", "Cameroun (le)", "CM", "CMR", "120"}, {"Canada", "Canada (le)", "CA", "CAN", "124"}, {"Cabo Verde", "Cabo Verde", "CV", "CPV", "132"}, {"Cayman Islands (the)", "Caïmans (les Îles)", "KY", "CYM", "136"}, {"Central African Republic (the)", "République centrafricaine (la)", "CF", "CAF", "140"}, {"Sri Lanka", "Sri Lanka", "LK", "LKA", "144"}, {"Chad", "Tchad (le)", "TD", "TCD", "148"}, {"Chile", "Chili (le)", "CL", "CHL", "152"}, {"China", "Chine (la)", "CN", "CHN", "156"}, {"Taiwan (Province of China)", "Taïwan (Province de Chine)", "TW", "TWN", "158"}, {"Christmas Island", "Christmas (l'Île)", "CX", "CXR", "162"}, {"Cocos (Keeling) Islands (the)", "Cocos (les Îles)/ Keeling (les Îles)", "CC", "CCK", "166"}, {"Colombia", "Colombie (la)", "CO", "COL", "170"}, {"Comoros (the)", "Comores (les)", "KM", "COM", "174"}, {"Mayotte", "Mayotte", "YT", "MYT", "175"}, {"Congo (the)", "Congo (le)", "CG", "COG", "178"}, {"Congo (the Democratic Republic of the)", "Congo (la République démocratique du)", "CD", "COD", "180"}, {"Cook Islands (the)", "Cook (les Îles)", "CK", "COK", "184"}, {"Costa Rica", "Costa Rica (le)", "CR", "CRI", "188"}, {"Croatia", "Croatie (la)", "HR", "HRV", "191"}, {"Cuba", "Cuba", "CU", "CUB", "192"}, {"Cyprus", "Chypre", "CY", "CYP", "196"}, {"Czech Republic (the)", "tchèque (la République)", "CZ", "CZE", "203"}, {"Benin", "Bénin (le)", "BJ", "BEN", "204"}, {"Denmark", "Danemark (le)", "DK", "DNK", "208"}, {"Dominica", "Dominique (la)", "DM", "DMA", "212"}, {"Dominican Republic (the)", "dominicaine (la République)", "DO", "DOM", "214"}, {"Ecuador", "Équateur (l')", "EC", "ECU", "218"}, {"El Salvador", "El Salvador", "SV", "SLV", "222"}, {"Equatorial Guinea", "Guinée équatoriale (la)", "GQ", "GNQ", "226"}, {"Ethiopia", "Éthiopie (l')", "ET", "ETH", "231"}, {"Eritrea", "Érythrée (l')", "ER", "ERI", "232"}, {"Estonia", "Estonie (l')", "EE", "EST", "233"}, {"Faroe Islands (the)", "Féroé (les Îles)", "FO", "FRO", "234"}, {"Falkland Islands (the) [Malvinas]", "Falkland (les Îles)/Malouines (les Îles)", "FK", "FLK", "238"}, {"South Georgia and the South Sandwich Islands", "Géorgie du Sud-et-les Îles Sandwich du Sud (la)", "GS", "SGS", "239"}, {"Fiji", "Fidji (les)", "FJ", "FJI", "242"}, {"Finland", "Finlande (la)", "FI", "FIN", "246"}, {"Åland Islands", "Åland(les Îles)", "AX", "ALA", "248"}, {"France", "France (la)", "FR", "FRA", "250"}, {"French Guiana", "Guyane française (la )", "GF", "GUF", "254"}, {"French Polynesia", "Polynésie française (la)", "PF", "PYF", "258"}, {"French Southern Territories (the)", "Terres australes françaises (les)", "TF", "ATF", "260"}, {"Djibouti", "Djibouti", "DJ", "DJI", "262"}, {"Gabon", "Gabon (le)", "GA", "GAB", "266"}, {"Georgia", "Géorgie (la)", "GE", "GEO", "268"}, {"Gambia (the)", "Gambie (la)", "GM", "GMB", "270"}, {"Palestine, State of", "Palestine, État de", "PS", "PSE", "275"}, {"Germany", "Allemagne (l')", "DE", "DEU", "276"}, {"Ghana", "Ghana (le)", "GH", "GHA", "288"}, {"Gibraltar", "Gibraltar", "GI", "GIB", "292"}, {"Kiribati", "Kiribati", "KI", "KIR", "296"}, {"Greece", "Grèce (la)", "GR", "GRC", "300"}, {"Greenland", "Groenland (le)", "GL", "GRL", "304"}, {"Grenada", "Grenade (la)", "GD", "GRD", "308"}, {"Guadeloupe", "Guadeloupe (la)", "GP", "GLP", "312"}, {"Guam", "Guam", "GU", "GUM", "316"}, {"Guatemala", "Guatemala (le)", "GT", "GTM", "320"}, {"Guinea", "Guinée (la)", "GN", "GIN", "324"}, {"Guyana", "Guyana (le)", "GY", "GUY", "328"}, {"Haiti", "Haïti", "HT", "HTI", "332"}, {"Heard Island and McDonald Islands", "Heard-et-Îles MacDonald (l'Île)", "HM", "HMD", "334"}, {"Holy See (the)", "Saint-Siège (le)", "VA", "VAT", "336"}, {"Honduras", "Honduras (le)", "HN", "HND", "340"}, {"Hong Kong", "Hong Kong", "HK", "HKG", "344"}, {"Hungary", "Hongrie (la)", "HU", "HUN", "348"}, {"Iceland", "Islande (l')", "IS", "ISL", "352"}, {"India", "Inde (l')", "IN", "IND", "356"}, {"Indonesia", "Indonésie (l')", "ID", "IDN", "360"}, {"Iran (Islamic Republic of)", "Iran (République Islamique d')", "IR", "IRN", "364"}, {"Iraq", "Iraq (l')", "IQ", "IRQ", "368"}, {"Ireland", "Irlande (l')", "IE", "IRL", "372"}, {"Israel", "Israël", "IL", "ISR", "376"}, {"Italy", "Italie (l')", "IT", "ITA", "380"}, {"Côte d'Ivoire", "Côte d'Ivoire (la)", "CI", "CIV", "384"}, {"Jamaica", "Jamaïque (la)", "JM", "JAM", "388"}, {"Japan", "Japon (le)", "JP", "JPN", "392"}, {"Kazakhstan", "Kazakhstan (le)", "KZ", "KAZ", "398"}, {"Jordan", "Jordanie (la)", "JO", "JOR", "400"}, {"Kenya", "Kenya (le)", "KE", "KEN", "404"}, {"Korea (the Democratic People's Republic of)", "Corée (la République populaire démocratique de)", "KP", "PRK", "408"}, {"Korea (the Republic of)", "Corée (la République de)", "KR", "KOR", "410"}, {"Kuwait", "Koweït (le)", "KW", "KWT", "414"}, {"Kyrgyzstan", "Kirghizistan (le)", "KG", "KGZ", "417"}, {"Lao People's Democratic Republic (the)", "Lao, République démocratique populaire", "LA", "LAO", "418"}, {"Lebanon", "Liban (le)", "LB", "LBN", "422"}, {"Lesotho", "Lesotho (le)", "LS", "LSO", "426"}, {"Latvia", "Lettonie (la)", "LV", "LVA", "428"}, {"Liberia", "Libéria (le)", "LR", "LBR", "430"}, {"Libya", "Libye (la)", "LY", "LBY", "434"}, {"Liechtenstein", "Liechtenstein (le)", "LI", "LIE", "438"}, {"Lithuania", "Lituanie (la)", "LT", "LTU", "440"}, {"Luxembourg", "Luxembourg (le)", "LU", "LUX", "442"}, {"Macao", "Macao", "MO", "MAC", "446"}, {"Madagascar", "Madagascar", "MG", "MDG", "450"}, {"Malawi", "Malawi (le)", "MW", "MWI", "454"}, {"Malaysia", "Malaisie (la)", "MY", "MYS", "458"}, {"Maldives", "Maldives (les)", "MV", "MDV", "462"}, {"Mali", "Mali (le)", "ML", "MLI", "466"}, {"Malta", "Malte", "MT", "MLT", "470"}, {"Martinique", "Martinique (la)", "MQ", "MTQ", "474"}, {"Mauritania", "Mauritanie (la)", "MR", "MRT", "478"}, {"Mauritius", "Maurice", "MU", "MUS", "480"}, {"Mexico", "Mexique (le)", "MX", "MEX", "484"}, {"Monaco", "Monaco", "MC", "MCO", "492"}, {"Mongolia", "Mongolie (la)", "MN", "MNG", "496"}, {"Moldova (the Republic of)", "Moldova , République de", "MD", "MDA", "498"}, {"Montenegro", "Monténégro (le)", "ME", "MNE", "499"}, {"Montserrat", "Montserrat", "MS", "MSR", "500"}, {"Morocco", "Maroc (le)", "MA", "MAR", "504"}, {"Mozambique", "Mozambique (le)", "MZ", "MOZ", "508"}, {"Oman", "Oman", "OM", "OMN", "512"}, {"Namibia", "Namibie (la)", "NA", "NAM", "516"}, {"Nauru", "Nauru", "NR", "NRU", "520"}, {"Nepal", "Népal (le)", "NP", "NPL", "524"}, {"Netherlands (the)", "Pays-Bas (les)", "NL", "NLD", "528"}, {"Curaçao", "Curaçao", "CW", "CUW", "531"}, {"Aruba", "Aruba", "AW", "ABW", "533"}, {"Sint Maarten (Dutch part)", "Saint-Martin (partie néerlandaise)", "SX", "SXM", "534"}, {"Bonaire, Sint Eustatius and Saba", "Bonaire, Saint-Eustache et Saba", "BQ", "BES", "535"}, {"New Caledonia", "Nouvelle-Calédonie (la)", "NC", "NCL", "540"}, {"Vanuatu", "Vanuatu (le)", "VU", "VUT", "548"}, {"New Zealand", "Nouvelle-Zélande (la)", "NZ", "NZL", "554"}, {"Nicaragua", "Nicaragua (le)", "NI", "NIC", "558"}, {"Niger (the)", "Niger (le)", "NE", "NER", "562"}, {"Nigeria", "Nigéria (le)", "NG", "NGA", "566"}, {"Niue", "Niue", "NU", "NIU", "570"}, {"Norfolk Island", "Norfolk (l'Île)", "NF", "NFK", "574"}, {"Norway", "Norvège (la)", "NO", "NOR", "578"}, {"Northern Mariana Islands (the)", "Mariannes du Nord (les Îles)", "MP", "MNP", "580"}, {"United States Minor Outlying Islands (the)", "Îles mineures éloignées des États-Unis (les)", "UM", "UMI", "581"}, {"Micronesia (Federated States of)", "Micronésie (États fédérés de)", "FM", "FSM", "583"}, {"Marshall Islands (the)", "Marshall (Îles)", "MH", "MHL", "584"}, {"Palau", "Palaos (les)", "PW", "PLW", "585"}, {"Pakistan", "Pakistan (le)", "PK", "PAK", "586"}, {"Panama", "Panama (le)", "PA", "PAN", "591"}, {"Papua New Guinea", "Papouasie-Nouvelle-Guinée (la)", "PG", "PNG", "598"}, {"Paraguay", "Paraguay (le)", "PY", "PRY", "600"}, {"Peru", "Pérou (le)", "PE", "PER", "604"}, {"Philippines (the)", "Philippines (les)", "PH", "PHL", "608"}, {"Pitcairn", "Pitcairn", "PN", "PCN", "612"}, {"Poland", "Pologne (la)", "PL", "POL", "616"}, {"Portugal", "Portugal (le)", "PT", "PRT", "620"}, {"Guinea-Bissau", "Guinée-Bissau (la)", "GW", "GNB", "624"}, {"Timor-Leste", "Timor-Leste (le)", "TL", "TLS", "626"}, {"Puerto Rico", "Porto Rico", "PR", "PRI", "630"}, {"Qatar", "Qatar (le)", "QA", "QAT", "634"}, {"Réunion", "Réunion (La)", "RE", "REU", "638"}, {"Romania", "Roumanie (la)", "RO", "ROU", "642"}, {"Russian Federation (the)", "Russie (la Fédération de)", "RU", "RUS", "643"}, {"Rwanda", "Rwanda (le)", "RW", "RWA", "646"}, {"Saint Barthélemy", "Saint-Barthélemy", "BL", "BLM", "652"}, {"Saint Helena, Ascension and Tristan da Cunha", "Sainte-Hélène, Ascension et Tristan da Cunha", "SH", "SHN", "654"}, {"Saint Kitts and Nevis", "Saint-Kitts-et-Nevis", "KN", "KNA", "659"}, {"Anguilla", "Anguilla", "AI", "AIA", "660"}, {"Saint Lucia", "Sainte-Lucie", "LC", "LCA", "662"}, {"Saint Martin (French part)", "Saint-Martin (partie française)", "MF", "MAF", "663"}, {"Saint Pierre and Miquelon", "Saint-Pierre-et-Miquelon", "PM", "SPM", "666"}, {"Saint Vincent and the Grenadines", "Saint-Vincent-et-les Grenadines", "VC", "VCT", "670"}, {"San Marino", "Saint-Marin", "SM", "SMR", "674"}, {"Sao Tome and Principe", "Sao Tomé-et-Principe", "ST", "STP", "678"}, {"Saudi Arabia", "Arabie saoudite (l')", "SA", "SAU", "682"}, {"Senegal", "Sénégal (le)", "SN", "SEN", "686"}, {"Serbia", "Serbie (la)", "RS", "SRB", "688"}, {"Seychelles", "Seychelles (les)", "SC", "SYC", "690"}, {"Sierra Leone", "Sierra Leone (la)", "SL", "SLE", "694"}, {"Singapore", "Singapour", "SG", "SGP", "702"}, {"Slovakia", "Slovaquie (la)", "SK", "SVK", "703"}, {"Viet Nam", "Viet Nam (le)", "VN", "VNM", "704"}, {"Slovenia", "Slovénie (la)", "SI", "SVN", "705"}, {"Somalia", "Somalie (la)", "SO", "SOM", "706"}, {"South Africa", "Afrique du Sud (l')", "ZA", "ZAF", "710"}, {"Zimbabwe", "Zimbabwe (le)", "ZW", "ZWE", "716"}, {"Spain", "Espagne (l')", "ES", "ESP", "724"}, {"South Sudan", "Soudan du Sud (le)", "SS", "SSD", "728"}, {"Sudan (the)", "Soudan (le)", "SD", "SDN", "729"}, {"Western Sahara*", "Sahara occidental (le)*", "EH", "ESH", "732"}, {"Suriname", "Suriname (le)", "SR", "SUR", "740"}, {"Svalbard and Jan Mayen", "Svalbard et l'Île Jan Mayen (le)", "SJ", "SJM", "744"}, {"Swaziland", "Swaziland (le)", "SZ", "SWZ", "748"}, {"Sweden", "Suède (la)", "SE", "SWE", "752"}, {"Switzerland", "Suisse (la)", "CH", "CHE", "756"}, {"Syrian Arab Republic", "République arabe syrienne (la)", "SY", "SYR", "760"}, {"Tajikistan", "Tadjikistan (le)", "TJ", "TJK", "762"}, {"Thailand", "Thaïlande (la)", "TH", "THA", "764"}, {"Togo", "Togo (le)", "TG", "TGO", "768"}, {"Tokelau", "Tokelau (les)", "TK", "TKL", "772"}, {"Tonga", "Tonga (les)", "TO", "TON", "776"}, {"Trinidad and Tobago", "Trinité-et-Tobago (la)", "TT", "TTO", "780"}, {"United Arab Emirates (the)", "Émirats arabes unis (les)", "AE", "ARE", "784"}, {"Tunisia", "Tunisie (la)", "TN", "TUN", "788"}, {"Turkey", "Turquie (la)", "TR", "TUR", "792"}, {"Turkmenistan", "Turkménistan (le)", "TM", "TKM", "795"}, {"Turks and Caicos Islands (the)", "Turks-et-Caïcos (les Îles)", "TC", "TCA", "796"}, {"Tuvalu", "Tuvalu (les)", "TV", "TUV", "798"}, {"Uganda", "Ouganda (l')", "UG", "UGA", "800"}, {"Ukraine", "Ukraine (l')", "UA", "UKR", "804"}, {"Macedonia (the former Yugoslav Republic of)", "Macédoine (l'ex‑République yougoslave de)", "MK", "MKD", "807"}, {"Egypt", "Égypte (l')", "EG", "EGY", "818"}, {"United Kingdom of Great Britain and Northern Ireland (the)", "Royaume-Uni de Grande-Bretagne et d'Irlande du Nord (le)", "GB", "GBR", "826"}, {"Guernsey", "Guernesey", "GG", "GGY", "831"}, {"Jersey", "Jersey", "JE", "JEY", "832"}, {"Isle of Man", "Île de Man", "IM", "IMN", "833"}, {"Tanzania, United Republic of", "Tanzanie, République-Unie de", "TZ", "TZA", "834"}, {"United States of America (the)", "États-Unis d'Amérique (les)", "US", "USA", "840"}, {"Virgin Islands (U.S.)", "Vierges des États-Unis (les Îles)", "VI", "VIR", "850"}, {"Burkina Faso", "Burkina Faso (le)", "BF", "BFA", "854"}, {"Uruguay", "Uruguay (l')", "UY", "URY", "858"}, {"Uzbekistan", "Ouzbékistan (l')", "UZ", "UZB", "860"}, {"Venezuela (Bolivarian Republic of)", "Venezuela (République bolivarienne du)", "VE", "VEN", "862"}, {"Wallis and Futuna", "Wallis-et-Futuna", "WF", "WLF", "876"}, {"Samoa", "Samoa (le)", "WS", "WSM", "882"}, {"Yemen", "Yémen (le)", "YE", "YEM", "887"}, {"Zambia", "Zambie (la)", "ZM", "ZMB", "894"}, } // ISO4217List is the list of ISO currency codes var ISO4217List = []string{ "AED", "AFN", "ALL", "AMD", "ANG", "AOA", "ARS", "AUD", "AWG", "AZN", "BAM", "BBD", "BDT", "BGN", "BHD", "BIF", "BMD", "BND", "BOB", "BOV", "BRL", "BSD", "BTN", "BWP", "BYN", "BZD", "CAD", "CDF", "CHE", "CHF", "CHW", "CLF", "CLP", "CNY", "COP", "COU", "CRC", "CUC", "CUP", "CVE", "CZK", "DJF", "DKK", "DOP", "DZD", "EGP", "ERN", "ETB", "EUR", "FJD", "FKP", "GBP", "GEL", "GHS", "GIP", "GMD", "GNF", "GTQ", "GYD", "HKD", "HNL", "HRK", "HTG", "HUF", "IDR", "ILS", "INR", "IQD", "IRR", "ISK", "JMD", "JOD", "JPY", "KES", "KGS", "KHR", "KMF", "KPW", "KRW", "KWD", "KYD", "KZT", "LAK", "LBP", "LKR", "LRD", "LSL", "LYD", "MAD", "MDL", "MGA", "MKD", "MMK", "MNT", "MOP", "MRO", "MUR", "MVR", "MWK", "MXN", "MXV", "MYR", "MZN", "NAD", "NGN", "NIO", "NOK", "NPR", "NZD", "OMR", "PAB", "PEN", "PGK", "PHP", "PKR", "PLN", "PYG", "QAR", "RON", "RSD", "RUB", "RWF", "SAR", "SBD", "SCR", "SDG", "SEK", "SGD", "SHP", "SLL", "SOS", "SRD", "SSP", "STD", "STN", "SVC", "SYP", "SZL", "THB", "TJS", "TMT", "TND", "TOP", "TRY", "TTD", "TWD", "TZS", "UAH", "UGX", "USD", "USN", "UYI", "UYU", "UYW", "UZS", "VEF", "VES", "VND", "VUV", "WST", "XAF", "XAG", "XAU", "XBA", "XBB", "XBC", "XBD", "XCD", "XDR", "XOF", "XPD", "XPF", "XPT", "XSU", "XTS", "XUA", "XXX", "YER", "ZAR", "ZMW", "ZWL", } // ISO693Entry stores ISO language codes type ISO693Entry struct { Alpha3bCode string Alpha2Code string English string } //ISO693List based on http://data.okfn.org/data/core/language-codes/r/language-codes-3b2.json var ISO693List = []ISO693Entry{ {Alpha3bCode: "aar", Alpha2Code: "aa", English: "Afar"}, {Alpha3bCode: "abk", Alpha2Code: "ab", English: "Abkhazian"}, {Alpha3bCode: "afr", Alpha2Code: "af", English: "Afrikaans"}, {Alpha3bCode: "aka", Alpha2Code: "ak", English: "Akan"}, {Alpha3bCode: "alb", Alpha2Code: "sq", English: "Albanian"}, {Alpha3bCode: "amh", Alpha2Code: "am", English: "Amharic"}, {Alpha3bCode: "ara", Alpha2Code: "ar", English: "Arabic"}, {Alpha3bCode: "arg", Alpha2Code: "an", English: "Aragonese"}, {Alpha3bCode: "arm", Alpha2Code: "hy", English: "Armenian"}, {Alpha3bCode: "asm", Alpha2Code: "as", English: "Assamese"}, {Alpha3bCode: "ava", Alpha2Code: "av", English: "Avaric"}, {Alpha3bCode: "ave", Alpha2Code: "ae", English: "Avestan"}, {Alpha3bCode: "aym", Alpha2Code: "ay", English: "Aymara"}, {Alpha3bCode: "aze", Alpha2Code: "az", English: "Azerbaijani"}, {Alpha3bCode: "bak", Alpha2Code: "ba", English: "Bashkir"}, {Alpha3bCode: "bam", Alpha2Code: "bm", English: "Bambara"}, {Alpha3bCode: "baq", Alpha2Code: "eu", English: "Basque"}, {Alpha3bCode: "bel", Alpha2Code: "be", English: "Belarusian"}, {Alpha3bCode: "ben", Alpha2Code: "bn", English: "Bengali"}, {Alpha3bCode: "bih", Alpha2Code: "bh", English: "Bihari languages"}, {Alpha3bCode: "bis", Alpha2Code: "bi", English: "Bislama"}, {Alpha3bCode: "bos", Alpha2Code: "bs", English: "Bosnian"}, {Alpha3bCode: "bre", Alpha2Code: "br", English: "Breton"}, {Alpha3bCode: "bul", Alpha2Code: "bg", English: "Bulgarian"}, {Alpha3bCode: "bur", Alpha2Code: "my", English: "Burmese"}, {Alpha3bCode: "cat", Alpha2Code: "ca", English: "Catalan; Valencian"}, {Alpha3bCode: "cha", Alpha2Code: "ch", English: "Chamorro"}, {Alpha3bCode: "che", Alpha2Code: "ce", English: "Chechen"}, {Alpha3bCode: "chi", Alpha2Code: "zh", English: "Chinese"}, {Alpha3bCode: "chu", Alpha2Code: "cu", English: "Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic"}, {Alpha3bCode: "chv", Alpha2Code: "cv", English: "Chuvash"}, {Alpha3bCode: "cor", Alpha2Code: "kw", English: "Cornish"}, {Alpha3bCode: "cos", Alpha2Code: "co", English: "Corsican"}, {Alpha3bCode: "cre", Alpha2Code: "cr", English: "Cree"}, {Alpha3bCode: "cze", Alpha2Code: "cs", English: "Czech"}, {Alpha3bCode: "dan", Alpha2Code: "da", English: "Danish"}, {Alpha3bCode: "div", Alpha2Code: "dv", English: "Divehi; Dhivehi; Maldivian"}, {Alpha3bCode: "dut", Alpha2Code: "nl", English: "Dutch; Flemish"}, {Alpha3bCode: "dzo", Alpha2Code: "dz", English: "Dzongkha"}, {Alpha3bCode: "eng", Alpha2Code: "en", English: "English"}, {Alpha3bCode: "epo", Alpha2Code: "eo", English: "Esperanto"}, {Alpha3bCode: "est", Alpha2Code: "et", English: "Estonian"}, {Alpha3bCode: "ewe", Alpha2Code: "ee", English: "Ewe"}, {Alpha3bCode: "fao", Alpha2Code: "fo", English: "Faroese"}, {Alpha3bCode: "fij", Alpha2Code: "fj", English: "Fijian"}, {Alpha3bCode: "fin", Alpha2Code: "fi", English: "Finnish"}, {Alpha3bCode: "fre", Alpha2Code: "fr", English: "French"}, {Alpha3bCode: "fry", Alpha2Code: "fy", English: "Western Frisian"}, {Alpha3bCode: "ful", Alpha2Code: "ff", English: "Fulah"}, {Alpha3bCode: "geo", Alpha2Code: "ka", English: "Georgian"}, {Alpha3bCode: "ger", Alpha2Code: "de", English: "German"}, {Alpha3bCode: "gla", Alpha2Code: "gd", English: "Gaelic; Scottish Gaelic"}, {Alpha3bCode: "gle", Alpha2Code: "ga", English: "Irish"}, {Alpha3bCode: "glg", Alpha2Code: "gl", English: "Galician"}, {Alpha3bCode: "glv", Alpha2Code: "gv", English: "Manx"}, {Alpha3bCode: "gre", Alpha2Code: "el", English: "Greek, Modern (1453-)"}, {Alpha3bCode: "grn", Alpha2Code: "gn", English: "Guarani"}, {Alpha3bCode: "guj", Alpha2Code: "gu", English: "Gujarati"}, {Alpha3bCode: "hat", Alpha2Code: "ht", English: "Haitian; Haitian Creole"}, {Alpha3bCode: "hau", Alpha2Code: "ha", English: "Hausa"}, {Alpha3bCode: "heb", Alpha2Code: "he", English: "Hebrew"}, {Alpha3bCode: "her", Alpha2Code: "hz", English: "Herero"}, {Alpha3bCode: "hin", Alpha2Code: "hi", English: "Hindi"}, {Alpha3bCode: "hmo", Alpha2Code: "ho", English: "Hiri Motu"}, {Alpha3bCode: "hrv", Alpha2Code: "hr", English: "Croatian"}, {Alpha3bCode: "hun", Alpha2Code: "hu", English: "Hungarian"}, {Alpha3bCode: "ibo", Alpha2Code: "ig", English: "Igbo"}, {Alpha3bCode: "ice", Alpha2Code: "is", English: "Icelandic"}, {Alpha3bCode: "ido", Alpha2Code: "io", English: "Ido"}, {Alpha3bCode: "iii", Alpha2Code: "ii", English: "Sichuan Yi; Nuosu"}, {Alpha3bCode: "iku", Alpha2Code: "iu", English: "Inuktitut"}, {Alpha3bCode: "ile", Alpha2Code: "ie", English: "Interlingue; Occidental"}, {Alpha3bCode: "ina", Alpha2Code: "ia", English: "Interlingua (International Auxiliary Language Association)"}, {Alpha3bCode: "ind", Alpha2Code: "id", English: "Indonesian"}, {Alpha3bCode: "ipk", Alpha2Code: "ik", English: "Inupiaq"}, {Alpha3bCode: "ita", Alpha2Code: "it", English: "Italian"}, {Alpha3bCode: "jav", Alpha2Code: "jv", English: "Javanese"}, {Alpha3bCode: "jpn", Alpha2Code: "ja", English: "Japanese"}, {Alpha3bCode: "kal", Alpha2Code: "kl", English: "Kalaallisut; Greenlandic"}, {Alpha3bCode: "kan", Alpha2Code: "kn", English: "Kannada"}, {Alpha3bCode: "kas", Alpha2Code: "ks", English: "Kashmiri"}, {Alpha3bCode: "kau", Alpha2Code: "kr", English: "Kanuri"}, {Alpha3bCode: "kaz", Alpha2Code: "kk", English: "Kazakh"}, {Alpha3bCode: "khm", Alpha2Code: "km", English: "Central Khmer"}, {Alpha3bCode: "kik", Alpha2Code: "ki", English: "Kikuyu; Gikuyu"}, {Alpha3bCode: "kin", Alpha2Code: "rw", English: "Kinyarwanda"}, {Alpha3bCode: "kir", Alpha2Code: "ky", English: "Kirghiz; Kyrgyz"}, {Alpha3bCode: "kom", Alpha2Code: "kv", English: "Komi"}, {Alpha3bCode: "kon", Alpha2Code: "kg", English: "Kongo"}, {Alpha3bCode: "kor", Alpha2Code: "ko", English: "Korean"}, {Alpha3bCode: "kua", Alpha2Code: "kj", English: "Kuanyama; Kwanyama"}, {Alpha3bCode: "kur", Alpha2Code: "ku", English: "Kurdish"}, {Alpha3bCode: "lao", Alpha2Code: "lo", English: "Lao"}, {Alpha3bCode: "lat", Alpha2Code: "la", English: "Latin"}, {Alpha3bCode: "lav", Alpha2Code: "lv", English: "Latvian"}, {Alpha3bCode: "lim", Alpha2Code: "li", English: "Limburgan; Limburger; Limburgish"}, {Alpha3bCode: "lin", Alpha2Code: "ln", English: "Lingala"}, {Alpha3bCode: "lit", Alpha2Code: "lt", English: "Lithuanian"}, {Alpha3bCode: "ltz", Alpha2Code: "lb", English: "Luxembourgish; Letzeburgesch"}, {Alpha3bCode: "lub", Alpha2Code: "lu", English: "Luba-Katanga"}, {Alpha3bCode: "lug", Alpha2Code: "lg", English: "Ganda"}, {Alpha3bCode: "mac", Alpha2Code: "mk", English: "Macedonian"}, {Alpha3bCode: "mah", Alpha2Code: "mh", English: "Marshallese"}, {Alpha3bCode: "mal", Alpha2Code: "ml", English: "Malayalam"}, {Alpha3bCode: "mao", Alpha2Code: "mi", English: "Maori"}, {Alpha3bCode: "mar", Alpha2Code: "mr", English: "Marathi"}, {Alpha3bCode: "may", Alpha2Code: "ms", English: "Malay"}, {Alpha3bCode: "mlg", Alpha2Code: "mg", English: "Malagasy"}, {Alpha3bCode: "mlt", Alpha2Code: "mt", English: "Maltese"}, {Alpha3bCode: "mon", Alpha2Code: "mn", English: "Mongolian"}, {Alpha3bCode: "nau", Alpha2Code: "na", English: "Nauru"}, {Alpha3bCode: "nav", Alpha2Code: "nv", English: "Navajo; Navaho"}, {Alpha3bCode: "nbl", Alpha2Code: "nr", English: "Ndebele, South; South Ndebele"}, {Alpha3bCode: "nde", Alpha2Code: "nd", English: "Ndebele, North; North Ndebele"}, {Alpha3bCode: "ndo", Alpha2Code: "ng", English: "Ndonga"}, {Alpha3bCode: "nep", Alpha2Code: "ne", English: "Nepali"}, {Alpha3bCode: "nno", Alpha2Code: "nn", English: "Norwegian Nynorsk; Nynorsk, Norwegian"}, {Alpha3bCode: "nob", Alpha2Code: "nb", English: "Bokmål, Norwegian; Norwegian Bokmål"}, {Alpha3bCode: "nor", Alpha2Code: "no", English: "Norwegian"}, {Alpha3bCode: "nya", Alpha2Code: "ny", English: "Chichewa; Chewa; Nyanja"}, {Alpha3bCode: "oci", Alpha2Code: "oc", English: "Occitan (post 1500); Provençal"}, {Alpha3bCode: "oji", Alpha2Code: "oj", English: "Ojibwa"}, {Alpha3bCode: "ori", Alpha2Code: "or", English: "Oriya"}, {Alpha3bCode: "orm", Alpha2Code: "om", English: "Oromo"}, {Alpha3bCode: "oss", Alpha2Code: "os", English: "Ossetian; Ossetic"}, {Alpha3bCode: "pan", Alpha2Code: "pa", English: "Panjabi; Punjabi"}, {Alpha3bCode: "per", Alpha2Code: "fa", English: "Persian"}, {Alpha3bCode: "pli", Alpha2Code: "pi", English: "Pali"}, {Alpha3bCode: "pol", Alpha2Code: "pl", English: "Polish"}, {Alpha3bCode: "por", Alpha2Code: "pt", English: "Portuguese"}, {Alpha3bCode: "pus", Alpha2Code: "ps", English: "Pushto; Pashto"}, {Alpha3bCode: "que", Alpha2Code: "qu", English: "Quechua"}, {Alpha3bCode: "roh", Alpha2Code: "rm", English: "Romansh"}, {Alpha3bCode: "rum", Alpha2Code: "ro", English: "Romanian; Moldavian; Moldovan"}, {Alpha3bCode: "run", Alpha2Code: "rn", English: "Rundi"}, {Alpha3bCode: "rus", Alpha2Code: "ru", English: "Russian"}, {Alpha3bCode: "sag", Alpha2Code: "sg", English: "Sango"}, {Alpha3bCode: "san", Alpha2Code: "sa", English: "Sanskrit"}, {Alpha3bCode: "sin", Alpha2Code: "si", English: "Sinhala; Sinhalese"}, {Alpha3bCode: "slo", Alpha2Code: "sk", English: "Slovak"}, {Alpha3bCode: "slv", Alpha2Code: "sl", English: "Slovenian"}, {Alpha3bCode: "sme", Alpha2Code: "se", English: "Northern Sami"}, {Alpha3bCode: "smo", Alpha2Code: "sm", English: "Samoan"}, {Alpha3bCode: "sna", Alpha2Code: "sn", English: "Shona"}, {Alpha3bCode: "snd", Alpha2Code: "sd", English: "Sindhi"}, {Alpha3bCode: "som", Alpha2Code: "so", English: "Somali"}, {Alpha3bCode: "sot", Alpha2Code: "st", English: "Sotho, Southern"}, {Alpha3bCode: "spa", Alpha2Code: "es", English: "Spanish; Castilian"}, {Alpha3bCode: "srd", Alpha2Code: "sc", English: "Sardinian"}, {Alpha3bCode: "srp", Alpha2Code: "sr", English: "Serbian"}, {Alpha3bCode: "ssw", Alpha2Code: "ss", English: "Swati"}, {Alpha3bCode: "sun", Alpha2Code: "su", English: "Sundanese"}, {Alpha3bCode: "swa", Alpha2Code: "sw", English: "Swahili"}, {Alpha3bCode: "swe", Alpha2Code: "sv", English: "Swedish"}, {Alpha3bCode: "tah", Alpha2Code: "ty", English: "Tahitian"}, {Alpha3bCode: "tam", Alpha2Code: "ta", English: "Tamil"}, {Alpha3bCode: "tat", Alpha2Code: "tt", English: "Tatar"}, {Alpha3bCode: "tel", Alpha2Code: "te", English: "Telugu"}, {Alpha3bCode: "tgk", Alpha2Code: "tg", English: "Tajik"}, {Alpha3bCode: "tgl", Alpha2Code: "tl", English: "Tagalog"}, {Alpha3bCode: "tha", Alpha2Code: "th", English: "Thai"}, {Alpha3bCode: "tib", Alpha2Code: "bo", English: "Tibetan"}, {Alpha3bCode: "tir", Alpha2Code: "ti", English: "Tigrinya"}, {Alpha3bCode: "ton", Alpha2Code: "to", English: "Tonga (Tonga Islands)"}, {Alpha3bCode: "tsn", Alpha2Code: "tn", English: "Tswana"}, {Alpha3bCode: "tso", Alpha2Code: "ts", English: "Tsonga"}, {Alpha3bCode: "tuk", Alpha2Code: "tk", English: "Turkmen"}, {Alpha3bCode: "tur", Alpha2Code: "tr", English: "Turkish"}, {Alpha3bCode: "twi", Alpha2Code: "tw", English: "Twi"}, {Alpha3bCode: "uig", Alpha2Code: "ug", English: "Uighur; Uyghur"}, {Alpha3bCode: "ukr", Alpha2Code: "uk", English: "Ukrainian"}, {Alpha3bCode: "urd", Alpha2Code: "ur", English: "Urdu"}, {Alpha3bCode: "uzb", Alpha2Code: "uz", English: "Uzbek"}, {Alpha3bCode: "ven", Alpha2Code: "ve", English: "Venda"}, {Alpha3bCode: "vie", Alpha2Code: "vi", English: "Vietnamese"}, {Alpha3bCode: "vol", Alpha2Code: "vo", English: "Volapük"}, {Alpha3bCode: "wel", Alpha2Code: "cy", English: "Welsh"}, {Alpha3bCode: "wln", Alpha2Code: "wa", English: "Walloon"}, {Alpha3bCode: "wol", Alpha2Code: "wo", English: "Wolof"}, {Alpha3bCode: "xho", Alpha2Code: "xh", English: "Xhosa"}, {Alpha3bCode: "yid", Alpha2Code: "yi", English: "Yiddish"}, {Alpha3bCode: "yor", Alpha2Code: "yo", English: "Yoruba"}, {Alpha3bCode: "zha", Alpha2Code: "za", English: "Zhuang; Chuang"}, {Alpha3bCode: "zul", Alpha2Code: "zu", English: "Zulu"}, } govalidator-11.0.1/utils.go000066400000000000000000000175061402110523600155770ustar00rootroot00000000000000package govalidator import ( "errors" "fmt" "html" "math" "path" "regexp" "strings" "unicode" "unicode/utf8" ) // Contains checks if the string contains the substring. func Contains(str, substring string) bool { return strings.Contains(str, substring) } // Matches checks if string matches the pattern (pattern is regular expression) // In case of error return false func Matches(str, pattern string) bool { match, _ := regexp.MatchString(pattern, str) return match } // LeftTrim trims characters from the left side of the input. // If second argument is empty, it will remove leading spaces. func LeftTrim(str, chars string) string { if chars == "" { return strings.TrimLeftFunc(str, unicode.IsSpace) } r, _ := regexp.Compile("^[" + chars + "]+") return r.ReplaceAllString(str, "") } // RightTrim trims characters from the right side of the input. // If second argument is empty, it will remove trailing spaces. func RightTrim(str, chars string) string { if chars == "" { return strings.TrimRightFunc(str, unicode.IsSpace) } r, _ := regexp.Compile("[" + chars + "]+$") return r.ReplaceAllString(str, "") } // Trim trims characters from both sides of the input. // If second argument is empty, it will remove spaces. func Trim(str, chars string) string { return LeftTrim(RightTrim(str, chars), chars) } // WhiteList removes characters that do not appear in the whitelist. func WhiteList(str, chars string) string { pattern := "[^" + chars + "]+" r, _ := regexp.Compile(pattern) return r.ReplaceAllString(str, "") } // BlackList removes characters that appear in the blacklist. func BlackList(str, chars string) string { pattern := "[" + chars + "]+" r, _ := regexp.Compile(pattern) return r.ReplaceAllString(str, "") } // StripLow removes characters with a numerical value < 32 and 127, mostly control characters. // If keep_new_lines is true, newline characters are preserved (\n and \r, hex 0xA and 0xD). func StripLow(str string, keepNewLines bool) string { chars := "" if keepNewLines { chars = "\x00-\x09\x0B\x0C\x0E-\x1F\x7F" } else { chars = "\x00-\x1F\x7F" } return BlackList(str, chars) } // ReplacePattern replaces regular expression pattern in string func ReplacePattern(str, pattern, replace string) string { r, _ := regexp.Compile(pattern) return r.ReplaceAllString(str, replace) } // Escape replaces <, >, & and " with HTML entities. var Escape = html.EscapeString func addSegment(inrune, segment []rune) []rune { if len(segment) == 0 { return inrune } if len(inrune) != 0 { inrune = append(inrune, '_') } inrune = append(inrune, segment...) return inrune } // UnderscoreToCamelCase converts from underscore separated form to camel case form. // Ex.: my_func => MyFunc func UnderscoreToCamelCase(s string) string { return strings.Replace(strings.Title(strings.Replace(strings.ToLower(s), "_", " ", -1)), " ", "", -1) } // CamelCaseToUnderscore converts from camel case form to underscore separated form. // Ex.: MyFunc => my_func func CamelCaseToUnderscore(str string) string { var output []rune var segment []rune for _, r := range str { // not treat number as separate segment if !unicode.IsLower(r) && string(r) != "_" && !unicode.IsNumber(r) { output = addSegment(output, segment) segment = nil } segment = append(segment, unicode.ToLower(r)) } output = addSegment(output, segment) return string(output) } // Reverse returns reversed string func Reverse(s string) string { r := []rune(s) for i, j := 0, len(r)-1; i < j; i, j = i+1, j-1 { r[i], r[j] = r[j], r[i] } return string(r) } // GetLines splits string by "\n" and return array of lines func GetLines(s string) []string { return strings.Split(s, "\n") } // GetLine returns specified line of multiline string func GetLine(s string, index int) (string, error) { lines := GetLines(s) if index < 0 || index >= len(lines) { return "", errors.New("line index out of bounds") } return lines[index], nil } // RemoveTags removes all tags from HTML string func RemoveTags(s string) string { return ReplacePattern(s, "<[^>]*>", "") } // SafeFileName returns safe string that can be used in file names func SafeFileName(str string) string { name := strings.ToLower(str) name = path.Clean(path.Base(name)) name = strings.Trim(name, " ") separators, err := regexp.Compile(`[ &_=+:]`) if err == nil { name = separators.ReplaceAllString(name, "-") } legal, err := regexp.Compile(`[^[:alnum:]-.]`) if err == nil { name = legal.ReplaceAllString(name, "") } for strings.Contains(name, "--") { name = strings.Replace(name, "--", "-", -1) } return name } // NormalizeEmail canonicalize an email address. // The local part of the email address is lowercased for all domains; the hostname is always lowercased and // the local part of the email address is always lowercased for hosts that are known to be case-insensitive (currently only GMail). // Normalization follows special rules for known providers: currently, GMail addresses have dots removed in the local part and // are stripped of tags (e.g. some.one+tag@gmail.com becomes someone@gmail.com) and all @googlemail.com addresses are // normalized to @gmail.com. func NormalizeEmail(str string) (string, error) { if !IsEmail(str) { return "", fmt.Errorf("%s is not an email", str) } parts := strings.Split(str, "@") parts[0] = strings.ToLower(parts[0]) parts[1] = strings.ToLower(parts[1]) if parts[1] == "gmail.com" || parts[1] == "googlemail.com" { parts[1] = "gmail.com" parts[0] = strings.Split(ReplacePattern(parts[0], `\.`, ""), "+")[0] } return strings.Join(parts, "@"), nil } // Truncate a string to the closest length without breaking words. func Truncate(str string, length int, ending string) string { var aftstr, befstr string if len(str) > length { words := strings.Fields(str) before, present := 0, 0 for i := range words { befstr = aftstr before = present aftstr = aftstr + words[i] + " " present = len(aftstr) if present > length && i != 0 { if (length - before) < (present - length) { return Trim(befstr, " /\\.,\"'#!?&@+-") + ending } return Trim(aftstr, " /\\.,\"'#!?&@+-") + ending } } } return str } // PadLeft pads left side of a string if size of string is less then indicated pad length func PadLeft(str string, padStr string, padLen int) string { return buildPadStr(str, padStr, padLen, true, false) } // PadRight pads right side of a string if size of string is less then indicated pad length func PadRight(str string, padStr string, padLen int) string { return buildPadStr(str, padStr, padLen, false, true) } // PadBoth pads both sides of a string if size of string is less then indicated pad length func PadBoth(str string, padStr string, padLen int) string { return buildPadStr(str, padStr, padLen, true, true) } // PadString either left, right or both sides. // Note that padding string can be unicode and more then one character func buildPadStr(str string, padStr string, padLen int, padLeft bool, padRight bool) string { // When padded length is less then the current string size if padLen < utf8.RuneCountInString(str) { return str } padLen -= utf8.RuneCountInString(str) targetLen := padLen targetLenLeft := targetLen targetLenRight := targetLen if padLeft && padRight { targetLenLeft = padLen / 2 targetLenRight = padLen - targetLenLeft } strToRepeatLen := utf8.RuneCountInString(padStr) repeatTimes := int(math.Ceil(float64(targetLen) / float64(strToRepeatLen))) repeatedString := strings.Repeat(padStr, repeatTimes) leftSide := "" if padLeft { leftSide = repeatedString[0:targetLenLeft] } rightSide := "" if padRight { rightSide = repeatedString[0:targetLenRight] } return leftSide + str + rightSide } // TruncatingErrorf removes extra args from fmt.Errorf if not formatted in the str object func TruncatingErrorf(str string, args ...interface{}) error { n := strings.Count(str, "%s") return fmt.Errorf(str, args[:n]...) } govalidator-11.0.1/utils_benchmark_test.go000066400000000000000000000005411402110523600206370ustar00rootroot00000000000000package govalidator import "testing" func BenchmarkContains(b *testing.B) { b.ResetTimer() for n := 0; n < b.N; n++ { Contains("a0b01c012deffghijklmnopqrstu0123456vwxyz", "0123456789") } } func BenchmarkMatches(b *testing.B) { b.ResetTimer() for n := 0; n < b.N; n++ { Matches("alfkjl12309fdjldfsa209jlksdfjLAKJjs9uJH234", "[\\w\\d]+") } } govalidator-11.0.1/utils_example_test.go000066400000000000000000000015131402110523600203400ustar00rootroot00000000000000package govalidator func ExampleTrim() { // Remove from left and right spaces and "\r", "\n", "\t" characters println(Trim(" \r\r\ntext\r \t\n", "") == "text") // Remove from left and right characters that are between "1" and "8". // "1-8" is like full list "12345678". println(Trim("1234567890987654321", "1-8") == "909") } func ExampleWhiteList() { // Remove all characters from string ignoring characters between "a" and "z" println(WhiteList("a3a43a5a4a3a2a23a4a5a4a3a4", "a-z") == "aaaaaaaaaaaa") } func ExampleReplacePattern() { // Replace in "http123123ftp://git534543hub.comio" following (pattern "(ftp|io|[0-9]+)"): // - Sequence "ftp". // - Sequence "io". // - Sequence of digits. // with empty string. println(ReplacePattern("http123123ftp://git534543hub.comio", "(ftp|io|[0-9]+)", "") == "http://github.com") } govalidator-11.0.1/utils_test.go000066400000000000000000000275451402110523600166420ustar00rootroot00000000000000package govalidator import ( "reflect" "testing" ) func TestContains(t *testing.T) { t.Parallel() var tests = []struct { param1 string param2 string expected bool }{ {"abacada", "", true}, {"abacada", "ritir", false}, {"abacada", "a", true}, {"abacada", "aca", true}, } for _, test := range tests { actual := Contains(test.param1, test.param2) if actual != test.expected { t.Errorf("Expected Contains(%q,%q) to be %v, got %v", test.param1, test.param2, test.expected, actual) } } } func TestMatches(t *testing.T) { t.Parallel() var tests = []struct { param1 string param2 string expected bool }{ {"123456789", "[0-9]+", true}, {"abacada", "cab$", false}, {"111222333", "((111|222|333)+)+", true}, {"abacaba", "((123+]", false}, } for _, test := range tests { actual := Matches(test.param1, test.param2) if actual != test.expected { t.Errorf("Expected Matches(%q,%q) to be %v, got %v", test.param1, test.param2, test.expected, actual) } } } func TestLeftTrim(t *testing.T) { t.Parallel() var tests = []struct { param1 string param2 string expected string }{ {" \r\n\tfoo \r\n\t ", "", "foo \r\n\t "}, {"010100201000", "01", "201000"}, } for _, test := range tests { actual := LeftTrim(test.param1, test.param2) if actual != test.expected { t.Errorf("Expected LeftTrim(%q,%q) to be %v, got %v", test.param1, test.param2, test.expected, actual) } } } func TestRightTrim(t *testing.T) { t.Parallel() var tests = []struct { param1 string param2 string expected string }{ {" \r\n\tfoo \r\n\t ", "", " \r\n\tfoo"}, {"010100201000", "01", "0101002"}, } for _, test := range tests { actual := RightTrim(test.param1, test.param2) if actual != test.expected { t.Errorf("Expected RightTrim(%q,%q) to be %v, got %v", test.param1, test.param2, test.expected, actual) } } } func TestTrim(t *testing.T) { t.Parallel() var tests = []struct { param1 string param2 string expected string }{ {" \r\n\tfoo \r\n\t ", "", "foo"}, {"010100201000", "01", "2"}, {"1234567890987654321", "1-8", "909"}, } for _, test := range tests { actual := Trim(test.param1, test.param2) if actual != test.expected { t.Errorf("Expected Trim(%q,%q) to be %v, got %v", test.param1, test.param2, test.expected, actual) } } } func TestWhiteList(t *testing.T) { t.Parallel() var tests = []struct { param1 string param2 string expected string }{ {"abcdef", "abc", "abc"}, {"aaaaaaaaaabbbbbbbbbb", "abc", "aaaaaaaaaabbbbbbbbbb"}, {"a1b2c3", "abc", "abc"}, {" ", "abc", ""}, {"a3a43a5a4a3a2a23a4a5a4a3a4", "a-z", "aaaaaaaaaaaa"}, } for _, test := range tests { actual := WhiteList(test.param1, test.param2) if actual != test.expected { t.Errorf("Expected WhiteList(%q,%q) to be %v, got %v", test.param1, test.param2, test.expected, actual) } } } func TestBlackList(t *testing.T) { t.Parallel() var tests = []struct { param1 string param2 string expected string }{ {"abcdef", "abc", "def"}, {"aaaaaaaaaabbbbbbbbbb", "abc", ""}, {"a1b2c3", "abc", "123"}, {" ", "abc", " "}, {"a3a43a5a4a3a2a23a4a5a4a3a4", "a-z", "34354322345434"}, } for _, test := range tests { actual := BlackList(test.param1, test.param2) if actual != test.expected { t.Errorf("Expected BlackList(%q,%q) to be %v, got %v", test.param1, test.param2, test.expected, actual) } } } func TestStripLow(t *testing.T) { t.Parallel() var tests = []struct { param1 string param2 bool expected string }{ {"foo\x00", false, "foo"}, {"\x7Ffoo\x02", false, "foo"}, {"\x01\x09", false, ""}, {"foo\x0A\x0D", false, "foo"}, {"perch\u00e9", false, "perch\u00e9"}, {"\u20ac", false, "\u20ac"}, {"\u2206\x0A", false, "\u2206"}, {"foo\x0A\x0D", true, "foo\x0A\x0D"}, {"\x03foo\x0A\x0D", true, "foo\x0A\x0D"}, } for _, test := range tests { actual := StripLow(test.param1, test.param2) if actual != test.expected { t.Errorf("Expected StripLow(%q,%t) to be %v, got %v", test.param1, test.param2, test.expected, actual) } } } func TestReplacePattern(t *testing.T) { t.Parallel() var tests = []struct { param1 string param2 string param3 string expected string }{ {"ab123ba", "[0-9]+", "aca", "abacaba"}, {"abacaba", "[0-9]+", "aca", "abacaba"}, {"httpftp://github.comio", "(ftp|io)", "", "http://github.com"}, {"aaaaaaaaaa", "a", "", ""}, {"http123123ftp://git534543hub.comio", "(ftp|io|[0-9]+)", "", "http://github.com"}, } for _, test := range tests { actual := ReplacePattern(test.param1, test.param2, test.param3) if actual != test.expected { t.Errorf("Expected ReplacePattern(%q,%q,%q) to be %v, got %v", test.param1, test.param2, test.param3, test.expected, actual) } } } func TestEscape(t *testing.T) { t.Parallel() var tests = []struct { param string expected string }{ {`foo&bar`, "<img alt="foo&bar">"}, } for _, test := range tests { actual := Escape(test.param) if actual != test.expected { t.Errorf("Expected Escape(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestUnderscoreToCamelCase(t *testing.T) { t.Parallel() var tests = []struct { param string expected string }{ {"a_b_c", "ABC"}, {"my_func", "MyFunc"}, {"1ab_cd", "1abCd"}, } for _, test := range tests { actual := UnderscoreToCamelCase(test.param) if actual != test.expected { t.Errorf("Expected UnderscoreToCamelCase(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestCamelCaseToUnderscore(t *testing.T) { t.Parallel() var tests = []struct { param string expected string }{ {"MyFunc", "my_func"}, {"ABC", "a_b_c"}, {"1B", "1_b"}, {"foo_bar", "foo_bar"}, {"FooV2Bar", "foo_v2_bar"}, } for _, test := range tests { actual := CamelCaseToUnderscore(test.param) if actual != test.expected { t.Errorf("Expected CamelCaseToUnderscore(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestReverse(t *testing.T) { t.Parallel() var tests = []struct { param string expected string }{ {"abc", "cba"}, {"カタカナ", "ナカタカ"}, } for _, test := range tests { actual := Reverse(test.param) if actual != test.expected { t.Errorf("Expected Reverse(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestGetLines(t *testing.T) { t.Parallel() var tests = []struct { param string expected []string }{ {"abc", []string{"abc"}}, {"a\nb\nc", []string{"a", "b", "c"}}, } for _, test := range tests { actual := GetLines(test.param) if !reflect.DeepEqual(actual, test.expected) { t.Errorf("Expected GetLines(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestGetLine(t *testing.T) { t.Parallel() var tests = []struct { param1 string param2 int expected string }{ {"abc", 0, "abc"}, {"a\nb\nc", 0, "a"}, {"abc", -1, ""}, {"abacaba\n", 1, ""}, {"abc", 3, ""}, } for _, test := range tests { actual, _ := GetLine(test.param1, test.param2) if actual != test.expected { t.Errorf("Expected GetLine(%q, %d) to be %v, got %v", test.param1, test.param2, test.expected, actual) } } } func TestRemoveTags(t *testing.T) { t.Parallel() var tests = []struct { param string expected string }{ {"abc", "abc"}, {"", ""}, {"

Text

", "Text"}, {`Link`, "Link"}, } for _, test := range tests { actual := RemoveTags(test.param) if actual != test.expected { t.Errorf("Expected RemoveTags(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestSafeFileName(t *testing.T) { t.Parallel() var tests = []struct { param string expected string }{ {"abc", "abc"}, {"123456789 '_-?ASDF@£$%£%^é.html", "123456789-asdf.html"}, {"ReadMe.md", "readme.md"}, {"file:///c:/test.go", "test.go"}, {"../../../Hello World!.txt", "hello-world.txt"}, } for _, test := range tests { actual := SafeFileName(test.param) if actual != test.expected { t.Errorf("Expected SafeFileName(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestNormalizeEmail(t *testing.T) { t.Parallel() var tests = []struct { param string expected string }{ {`test@me.com`, `test@me.com`}, {`some.name@gmail.com`, `somename@gmail.com`}, {`some.name@googlemail.com`, `somename@gmail.com`}, {`some.name+extension@gmail.com`, `somename@gmail.com`}, {`some.name+extension@googlemail.com`, `somename@gmail.com`}, {`some.name.middlename+extension@gmail.com`, `somenamemiddlename@gmail.com`}, {`some.name.middlename+extension@googlemail.com`, `somenamemiddlename@gmail.com`}, {`some.name.midd.lena.me.+extension@gmail.com`, `somenamemiddlename@gmail.com`}, {`some.name.midd.lena.me.+extension@googlemail.com`, `somenamemiddlename@gmail.com`}, {`some.name+extension@unknown.com`, `some.name+extension@unknown.com`}, // TODO: {`hans@m端ller.com`, `hans@m端ller.com`}, {`hans`, ``}, } for _, test := range tests { actual, err := NormalizeEmail(test.param) if actual != test.expected { t.Errorf("Expected NormalizeEmail(%q) to be %v, got %v, err %v", test.param, test.expected, actual, err) } } } func TestTruncate(t *testing.T) { t.Parallel() var tests = []struct { param1 string param2 int param3 string expected string }{ {`Lorem ipsum dolor sit amet, consectetur adipiscing elit.`, 25, `...`, `Lorem ipsum dolor sit amet...`}, {`Measuring programming progress by lines of code is like measuring aircraft building progress by weight.`, 35, ` new born babies!`, `Measuring programming progress by new born babies!`}, {`Testestestestestestestestestest testestestestestestestestest`, 7, `...`, `Testestestestestestestestestest...`}, {`Testing`, 7, `...`, `Testing`}, } for _, test := range tests { actual := Truncate(test.param1, test.param2, test.param3) if actual != test.expected { t.Errorf("Expected Truncate(%q, %d, %q) to be %v, got %v", test.param1, test.param2, test.param3, test.expected, actual) } } } func TestPadLeft(t *testing.T) { t.Parallel() var tests = []struct { param1 string param2 string param3 int expected string }{ {"こんにちは", "xyz", 12, "xyzxyzxこんにちは"}, {"こんにちは", "xyz", 11, "xyzxyzこんにちは"}, {"abc", "x", 5, "xxabc"}, {"abc", "xyz", 5, "xyabc"}, {"abcde", "xyz", 5, "abcde"}, {"abcde", "xyz", 4, "abcde"}, } for _, test := range tests { actual := PadLeft(test.param1, test.param2, test.param3) if actual != test.expected { t.Errorf("Expected PadLeft(%q,%q,%q) to be %v, got %v", test.param1, test.param2, test.param3, test.expected, actual) } } } func TestPadRight(t *testing.T) { t.Parallel() var tests = []struct { param1 string param2 string param3 int expected string }{ {"こんにちは", "xyz", 12, "こんにちはxyzxyzx"}, {"こんにちは", "xyz", 11, "こんにちはxyzxyz"}, {"abc", "x", 5, "abcxx"}, {"abc", "xyz", 5, "abcxy"}, {"abcde", "xyz", 5, "abcde"}, {"abcde", "xyz", 4, "abcde"}, } for _, test := range tests { actual := PadRight(test.param1, test.param2, test.param3) if actual != test.expected { t.Errorf("Expected PadRight(%q,%q,%q) to be %v, got %v", test.param1, test.param2, test.param3, test.expected, actual) } } } func TestPadBoth(t *testing.T) { t.Parallel() var tests = []struct { param1 string param2 string param3 int expected string }{ {"こんにちは", "xyz", 12, "xyzこんにちはxyzx"}, {"こんにちは", "xyz", 11, "xyzこんにちはxyz"}, {"abc", "x", 5, "xabcx"}, {"abc", "xyz", 5, "xabcx"}, {"abcde", "xyz", 5, "abcde"}, {"abcde", "xyz", 4, "abcde"}, } for _, test := range tests { actual := PadBoth(test.param1, test.param2, test.param3) if actual != test.expected { t.Errorf("Expected PadBoth(%q,%q,%q) to be %v, got %v", test.param1, test.param2, test.param3, test.expected, actual) } } } govalidator-11.0.1/validator.go000066400000000000000000001424251402110523600164230ustar00rootroot00000000000000// Package govalidator is package of validators and sanitizers for strings, structs and collections. package govalidator import ( "bytes" "crypto/rsa" "crypto/x509" "encoding/base64" "encoding/json" "encoding/pem" "fmt" "io/ioutil" "net" "net/url" "reflect" "regexp" "sort" "strconv" "strings" "time" "unicode" "unicode/utf8" ) var ( fieldsRequiredByDefault bool nilPtrAllowedByRequired = false notNumberRegexp = regexp.MustCompile("[^0-9]+") whiteSpacesAndMinus = regexp.MustCompile(`[\s-]+`) paramsRegexp = regexp.MustCompile(`\(.*\)$`) ) const maxURLRuneCount = 2083 const minURLRuneCount = 3 const rfc3339WithoutZone = "2006-01-02T15:04:05" // SetFieldsRequiredByDefault causes validation to fail when struct fields // do not include validations or are not explicitly marked as exempt (using `valid:"-"` or `valid:"email,optional"`). // This struct definition will fail govalidator.ValidateStruct() (and the field values do not matter): // type exampleStruct struct { // Name string `` // Email string `valid:"email"` // This, however, will only fail when Email is empty or an invalid email address: // type exampleStruct2 struct { // Name string `valid:"-"` // Email string `valid:"email"` // Lastly, this will only fail when Email is an invalid email address but not when it's empty: // type exampleStruct2 struct { // Name string `valid:"-"` // Email string `valid:"email,optional"` func SetFieldsRequiredByDefault(value bool) { fieldsRequiredByDefault = value } // SetNilPtrAllowedByRequired causes validation to pass for nil ptrs when a field is set to required. // The validation will still reject ptr fields in their zero value state. Example with this enabled: // type exampleStruct struct { // Name *string `valid:"required"` // With `Name` set to "", this will be considered invalid input and will cause a validation error. // With `Name` set to nil, this will be considered valid by validation. // By default this is disabled. func SetNilPtrAllowedByRequired(value bool) { nilPtrAllowedByRequired = value } // IsEmail checks if the string is an email. func IsEmail(str string) bool { // TODO uppercase letters are not supported return rxEmail.MatchString(str) } // IsExistingEmail checks if the string is an email of existing domain func IsExistingEmail(email string) bool { if len(email) < 6 || len(email) > 254 { return false } at := strings.LastIndex(email, "@") if at <= 0 || at > len(email)-3 { return false } user := email[:at] host := email[at+1:] if len(user) > 64 { return false } switch host { case "localhost", "example.com": return true } if userDotRegexp.MatchString(user) || !userRegexp.MatchString(user) || !hostRegexp.MatchString(host) { return false } if _, err := net.LookupMX(host); err != nil { if _, err := net.LookupIP(host); err != nil { return false } } return true } // IsURL checks if the string is an URL. func IsURL(str string) bool { if str == "" || utf8.RuneCountInString(str) >= maxURLRuneCount || len(str) <= minURLRuneCount || strings.HasPrefix(str, ".") { return false } strTemp := str if strings.Contains(str, ":") && !strings.Contains(str, "://") { // support no indicated urlscheme but with colon for port number // http:// is appended so url.Parse will succeed, strTemp used so it does not impact rxURL.MatchString strTemp = "http://" + str } u, err := url.Parse(strTemp) if err != nil { return false } if strings.HasPrefix(u.Host, ".") { return false } if u.Host == "" && (u.Path != "" && !strings.Contains(u.Path, ".")) { return false } return rxURL.MatchString(str) } // IsRequestURL checks if the string rawurl, assuming // it was received in an HTTP request, is a valid // URL confirm to RFC 3986 func IsRequestURL(rawurl string) bool { url, err := url.ParseRequestURI(rawurl) if err != nil { return false //Couldn't even parse the rawurl } if len(url.Scheme) == 0 { return false //No Scheme found } return true } // IsRequestURI checks if the string rawurl, assuming // it was received in an HTTP request, is an // absolute URI or an absolute path. func IsRequestURI(rawurl string) bool { _, err := url.ParseRequestURI(rawurl) return err == nil } // IsAlpha checks if the string contains only letters (a-zA-Z). Empty string is valid. func IsAlpha(str string) bool { if IsNull(str) { return true } return rxAlpha.MatchString(str) } //IsUTFLetter checks if the string contains only unicode letter characters. //Similar to IsAlpha but for all languages. Empty string is valid. func IsUTFLetter(str string) bool { if IsNull(str) { return true } for _, c := range str { if !unicode.IsLetter(c) { return false } } return true } // IsAlphanumeric checks if the string contains only letters and numbers. Empty string is valid. func IsAlphanumeric(str string) bool { if IsNull(str) { return true } return rxAlphanumeric.MatchString(str) } // IsUTFLetterNumeric checks if the string contains only unicode letters and numbers. Empty string is valid. func IsUTFLetterNumeric(str string) bool { if IsNull(str) { return true } for _, c := range str { if !unicode.IsLetter(c) && !unicode.IsNumber(c) { //letters && numbers are ok return false } } return true } // IsNumeric checks if the string contains only numbers. Empty string is valid. func IsNumeric(str string) bool { if IsNull(str) { return true } return rxNumeric.MatchString(str) } // IsUTFNumeric checks if the string contains only unicode numbers of any kind. // Numbers can be 0-9 but also Fractions ¾,Roman Ⅸ and Hangzhou 〩. Empty string is valid. func IsUTFNumeric(str string) bool { if IsNull(str) { return true } if strings.IndexAny(str, "+-") > 0 { return false } if len(str) > 1 { str = strings.TrimPrefix(str, "-") str = strings.TrimPrefix(str, "+") } for _, c := range str { if !unicode.IsNumber(c) { //numbers && minus sign are ok return false } } return true } // IsUTFDigit checks if the string contains only unicode radix-10 decimal digits. Empty string is valid. func IsUTFDigit(str string) bool { if IsNull(str) { return true } if strings.IndexAny(str, "+-") > 0 { return false } if len(str) > 1 { str = strings.TrimPrefix(str, "-") str = strings.TrimPrefix(str, "+") } for _, c := range str { if !unicode.IsDigit(c) { //digits && minus sign are ok return false } } return true } // IsHexadecimal checks if the string is a hexadecimal number. func IsHexadecimal(str string) bool { return rxHexadecimal.MatchString(str) } // IsHexcolor checks if the string is a hexadecimal color. func IsHexcolor(str string) bool { return rxHexcolor.MatchString(str) } // IsRGBcolor checks if the string is a valid RGB color in form rgb(RRR, GGG, BBB). func IsRGBcolor(str string) bool { return rxRGBcolor.MatchString(str) } // IsLowerCase checks if the string is lowercase. Empty string is valid. func IsLowerCase(str string) bool { if IsNull(str) { return true } return str == strings.ToLower(str) } // IsUpperCase checks if the string is uppercase. Empty string is valid. func IsUpperCase(str string) bool { if IsNull(str) { return true } return str == strings.ToUpper(str) } // HasLowerCase checks if the string contains at least 1 lowercase. Empty string is valid. func HasLowerCase(str string) bool { if IsNull(str) { return true } return rxHasLowerCase.MatchString(str) } // HasUpperCase checks if the string contains as least 1 uppercase. Empty string is valid. func HasUpperCase(str string) bool { if IsNull(str) { return true } return rxHasUpperCase.MatchString(str) } // IsInt checks if the string is an integer. Empty string is valid. func IsInt(str string) bool { if IsNull(str) { return true } return rxInt.MatchString(str) } // IsFloat checks if the string is a float. func IsFloat(str string) bool { return str != "" && rxFloat.MatchString(str) } // IsDivisibleBy checks if the string is a number that's divisible by another. // If second argument is not valid integer or zero, it's return false. // Otherwise, if first argument is not valid integer or zero, it's return true (Invalid string converts to zero). func IsDivisibleBy(str, num string) bool { f, _ := ToFloat(str) p := int64(f) q, _ := ToInt(num) if q == 0 { return false } return (p == 0) || (p%q == 0) } // IsNull checks if the string is null. func IsNull(str string) bool { return len(str) == 0 } // IsNotNull checks if the string is not null. func IsNotNull(str string) bool { return !IsNull(str) } // HasWhitespaceOnly checks the string only contains whitespace func HasWhitespaceOnly(str string) bool { return len(str) > 0 && rxHasWhitespaceOnly.MatchString(str) } // HasWhitespace checks if the string contains any whitespace func HasWhitespace(str string) bool { return len(str) > 0 && rxHasWhitespace.MatchString(str) } // IsByteLength checks if the string's length (in bytes) falls in a range. func IsByteLength(str string, min, max int) bool { return len(str) >= min && len(str) <= max } // IsUUIDv3 checks if the string is a UUID version 3. func IsUUIDv3(str string) bool { return rxUUID3.MatchString(str) } // IsUUIDv4 checks if the string is a UUID version 4. func IsUUIDv4(str string) bool { return rxUUID4.MatchString(str) } // IsUUIDv5 checks if the string is a UUID version 5. func IsUUIDv5(str string) bool { return rxUUID5.MatchString(str) } // IsUUID checks if the string is a UUID (version 3, 4 or 5). func IsUUID(str string) bool { return rxUUID.MatchString(str) } // Byte to index table for O(1) lookups when unmarshaling. // We use 0xFF as sentinel value for invalid indexes. var ulidDec = [...]byte{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0xFF, 0x12, 0x13, 0xFF, 0x14, 0x15, 0xFF, 0x16, 0x17, 0x18, 0x19, 0x1A, 0xFF, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0xFF, 0x12, 0x13, 0xFF, 0x14, 0x15, 0xFF, 0x16, 0x17, 0x18, 0x19, 0x1A, 0xFF, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, } // EncodedSize is the length of a text encoded ULID. const ulidEncodedSize = 26 // IsULID checks if the string is a ULID. // // Implementation got from: // https://github.com/oklog/ulid (Apache-2.0 License) // func IsULID(str string) bool { // Check if a base32 encoded ULID is the right length. if len(str) != ulidEncodedSize { return false } // Check if all the characters in a base32 encoded ULID are part of the // expected base32 character set. if ulidDec[str[0]] == 0xFF || ulidDec[str[1]] == 0xFF || ulidDec[str[2]] == 0xFF || ulidDec[str[3]] == 0xFF || ulidDec[str[4]] == 0xFF || ulidDec[str[5]] == 0xFF || ulidDec[str[6]] == 0xFF || ulidDec[str[7]] == 0xFF || ulidDec[str[8]] == 0xFF || ulidDec[str[9]] == 0xFF || ulidDec[str[10]] == 0xFF || ulidDec[str[11]] == 0xFF || ulidDec[str[12]] == 0xFF || ulidDec[str[13]] == 0xFF || ulidDec[str[14]] == 0xFF || ulidDec[str[15]] == 0xFF || ulidDec[str[16]] == 0xFF || ulidDec[str[17]] == 0xFF || ulidDec[str[18]] == 0xFF || ulidDec[str[19]] == 0xFF || ulidDec[str[20]] == 0xFF || ulidDec[str[21]] == 0xFF || ulidDec[str[22]] == 0xFF || ulidDec[str[23]] == 0xFF || ulidDec[str[24]] == 0xFF || ulidDec[str[25]] == 0xFF { return false } // Check if the first character in a base32 encoded ULID will overflow. This // happens because the base32 representation encodes 130 bits, while the // ULID is only 128 bits. // // See https://github.com/oklog/ulid/issues/9 for details. if str[0] > '7' { return false } return true } // IsCreditCard checks if the string is a credit card. func IsCreditCard(str string) bool { sanitized := whiteSpacesAndMinus.ReplaceAllString(str, "") if !rxCreditCard.MatchString(sanitized) { return false } var sum int64 var digit string var tmpNum int64 var shouldDouble bool for i := len(sanitized) - 1; i >= 0; i-- { digit = sanitized[i:(i + 1)] tmpNum, _ = ToInt(digit) if shouldDouble { tmpNum *= 2 if tmpNum >= 10 { sum += (tmpNum % 10) + 1 } else { sum += tmpNum } } else { sum += tmpNum } shouldDouble = !shouldDouble } return sum%10 == 0 } // IsISBN10 checks if the string is an ISBN version 10. func IsISBN10(str string) bool { return IsISBN(str, 10) } // IsISBN13 checks if the string is an ISBN version 13. func IsISBN13(str string) bool { return IsISBN(str, 13) } // IsISBN checks if the string is an ISBN (version 10 or 13). // If version value is not equal to 10 or 13, it will be checks both variants. func IsISBN(str string, version int) bool { sanitized := whiteSpacesAndMinus.ReplaceAllString(str, "") var checksum int32 var i int32 if version == 10 { if !rxISBN10.MatchString(sanitized) { return false } for i = 0; i < 9; i++ { checksum += (i + 1) * int32(sanitized[i]-'0') } if sanitized[9] == 'X' { checksum += 10 * 10 } else { checksum += 10 * int32(sanitized[9]-'0') } if checksum%11 == 0 { return true } return false } else if version == 13 { if !rxISBN13.MatchString(sanitized) { return false } factor := []int32{1, 3} for i = 0; i < 12; i++ { checksum += factor[i%2] * int32(sanitized[i]-'0') } return (int32(sanitized[12]-'0'))-((10-(checksum%10))%10) == 0 } return IsISBN(str, 10) || IsISBN(str, 13) } // IsJSON checks if the string is valid JSON (note: uses json.Unmarshal). func IsJSON(str string) bool { var js json.RawMessage return json.Unmarshal([]byte(str), &js) == nil } // IsMultibyte checks if the string contains one or more multibyte chars. Empty string is valid. func IsMultibyte(str string) bool { if IsNull(str) { return true } return rxMultibyte.MatchString(str) } // IsASCII checks if the string contains ASCII chars only. Empty string is valid. func IsASCII(str string) bool { if IsNull(str) { return true } return rxASCII.MatchString(str) } // IsPrintableASCII checks if the string contains printable ASCII chars only. Empty string is valid. func IsPrintableASCII(str string) bool { if IsNull(str) { return true } return rxPrintableASCII.MatchString(str) } // IsFullWidth checks if the string contains any full-width chars. Empty string is valid. func IsFullWidth(str string) bool { if IsNull(str) { return true } return rxFullWidth.MatchString(str) } // IsHalfWidth checks if the string contains any half-width chars. Empty string is valid. func IsHalfWidth(str string) bool { if IsNull(str) { return true } return rxHalfWidth.MatchString(str) } // IsVariableWidth checks if the string contains a mixture of full and half-width chars. Empty string is valid. func IsVariableWidth(str string) bool { if IsNull(str) { return true } return rxHalfWidth.MatchString(str) && rxFullWidth.MatchString(str) } // IsBase64 checks if a string is base64 encoded. func IsBase64(str string) bool { return rxBase64.MatchString(str) } // IsFilePath checks is a string is Win or Unix file path and returns it's type. func IsFilePath(str string) (bool, int) { if rxWinPath.MatchString(str) { //check windows path limit see: // http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx#maxpath if len(str[3:]) > 32767 { return false, Win } return true, Win } else if rxUnixPath.MatchString(str) { return true, Unix } return false, Unknown } //IsWinFilePath checks both relative & absolute paths in Windows func IsWinFilePath(str string) bool { if rxARWinPath.MatchString(str) { //check windows path limit see: // http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx#maxpath if len(str[3:]) > 32767 { return false } return true } return false } //IsUnixFilePath checks both relative & absolute paths in Unix func IsUnixFilePath(str string) bool { if rxARUnixPath.MatchString(str) { return true } return false } // IsDataURI checks if a string is base64 encoded data URI such as an image func IsDataURI(str string) bool { dataURI := strings.Split(str, ",") if !rxDataURI.MatchString(dataURI[0]) { return false } return IsBase64(dataURI[1]) } // IsMagnetURI checks if a string is valid magnet URI func IsMagnetURI(str string) bool { return rxMagnetURI.MatchString(str) } // IsISO3166Alpha2 checks if a string is valid two-letter country code func IsISO3166Alpha2(str string) bool { for _, entry := range ISO3166List { if str == entry.Alpha2Code { return true } } return false } // IsISO3166Alpha3 checks if a string is valid three-letter country code func IsISO3166Alpha3(str string) bool { for _, entry := range ISO3166List { if str == entry.Alpha3Code { return true } } return false } // IsISO693Alpha2 checks if a string is valid two-letter language code func IsISO693Alpha2(str string) bool { for _, entry := range ISO693List { if str == entry.Alpha2Code { return true } } return false } // IsISO693Alpha3b checks if a string is valid three-letter language code func IsISO693Alpha3b(str string) bool { for _, entry := range ISO693List { if str == entry.Alpha3bCode { return true } } return false } // IsDNSName will validate the given string as a DNS name func IsDNSName(str string) bool { if str == "" || len(strings.Replace(str, ".", "", -1)) > 255 { // constraints already violated return false } return !IsIP(str) && rxDNSName.MatchString(str) } // IsHash checks if a string is a hash of type algorithm. // Algorithm is one of ['md4', 'md5', 'sha1', 'sha256', 'sha384', 'sha512', 'ripemd128', 'ripemd160', 'tiger128', 'tiger160', 'tiger192', 'crc32', 'crc32b'] func IsHash(str string, algorithm string) bool { var len string algo := strings.ToLower(algorithm) if algo == "crc32" || algo == "crc32b" { len = "8" } else if algo == "md5" || algo == "md4" || algo == "ripemd128" || algo == "tiger128" { len = "32" } else if algo == "sha1" || algo == "ripemd160" || algo == "tiger160" { len = "40" } else if algo == "tiger192" { len = "48" } else if algo == "sha3-224" { len = "56" } else if algo == "sha256" || algo == "sha3-256" { len = "64" } else if algo == "sha384" || algo == "sha3-384" { len = "96" } else if algo == "sha512" || algo == "sha3-512" { len = "128" } else { return false } return Matches(str, "^[a-f0-9]{"+len+"}$") } // IsSHA3224 checks is a string is a SHA3-224 hash. Alias for `IsHash(str, "sha3-224")` func IsSHA3224(str string) bool { return IsHash(str, "sha3-224") } // IsSHA3256 checks is a string is a SHA3-256 hash. Alias for `IsHash(str, "sha3-256")` func IsSHA3256(str string) bool { return IsHash(str, "sha3-256") } // IsSHA3384 checks is a string is a SHA3-384 hash. Alias for `IsHash(str, "sha3-384")` func IsSHA3384(str string) bool { return IsHash(str, "sha3-384") } // IsSHA3512 checks is a string is a SHA3-512 hash. Alias for `IsHash(str, "sha3-512")` func IsSHA3512(str string) bool { return IsHash(str, "sha3-512") } // IsSHA512 checks is a string is a SHA512 hash. Alias for `IsHash(str, "sha512")` func IsSHA512(str string) bool { return IsHash(str, "sha512") } // IsSHA384 checks is a string is a SHA384 hash. Alias for `IsHash(str, "sha384")` func IsSHA384(str string) bool { return IsHash(str, "sha384") } // IsSHA256 checks is a string is a SHA256 hash. Alias for `IsHash(str, "sha256")` func IsSHA256(str string) bool { return IsHash(str, "sha256") } // IsTiger192 checks is a string is a Tiger192 hash. Alias for `IsHash(str, "tiger192")` func IsTiger192(str string) bool { return IsHash(str, "tiger192") } // IsTiger160 checks is a string is a Tiger160 hash. Alias for `IsHash(str, "tiger160")` func IsTiger160(str string) bool { return IsHash(str, "tiger160") } // IsRipeMD160 checks is a string is a RipeMD160 hash. Alias for `IsHash(str, "ripemd160")` func IsRipeMD160(str string) bool { return IsHash(str, "ripemd160") } // IsSHA1 checks is a string is a SHA-1 hash. Alias for `IsHash(str, "sha1")` func IsSHA1(str string) bool { return IsHash(str, "sha1") } // IsTiger128 checks is a string is a Tiger128 hash. Alias for `IsHash(str, "tiger128")` func IsTiger128(str string) bool { return IsHash(str, "tiger128") } // IsRipeMD128 checks is a string is a RipeMD128 hash. Alias for `IsHash(str, "ripemd128")` func IsRipeMD128(str string) bool { return IsHash(str, "ripemd128") } // IsCRC32 checks is a string is a CRC32 hash. Alias for `IsHash(str, "crc32")` func IsCRC32(str string) bool { return IsHash(str, "crc32") } // IsCRC32b checks is a string is a CRC32b hash. Alias for `IsHash(str, "crc32b")` func IsCRC32b(str string) bool { return IsHash(str, "crc32b") } // IsMD5 checks is a string is a MD5 hash. Alias for `IsHash(str, "md5")` func IsMD5(str string) bool { return IsHash(str, "md5") } // IsMD4 checks is a string is a MD4 hash. Alias for `IsHash(str, "md4")` func IsMD4(str string) bool { return IsHash(str, "md4") } // IsDialString validates the given string for usage with the various Dial() functions func IsDialString(str string) bool { if h, p, err := net.SplitHostPort(str); err == nil && h != "" && p != "" && (IsDNSName(h) || IsIP(h)) && IsPort(p) { return true } return false } // IsIP checks if a string is either IP version 4 or 6. Alias for `net.ParseIP` func IsIP(str string) bool { return net.ParseIP(str) != nil } // IsPort checks if a string represents a valid port func IsPort(str string) bool { if i, err := strconv.Atoi(str); err == nil && i > 0 && i < 65536 { return true } return false } // IsIPv4 checks if the string is an IP version 4. func IsIPv4(str string) bool { ip := net.ParseIP(str) return ip != nil && strings.Contains(str, ".") } // IsIPv6 checks if the string is an IP version 6. func IsIPv6(str string) bool { ip := net.ParseIP(str) return ip != nil && strings.Contains(str, ":") } // IsCIDR checks if the string is an valid CIDR notiation (IPV4 & IPV6) func IsCIDR(str string) bool { _, _, err := net.ParseCIDR(str) return err == nil } // IsMAC checks if a string is valid MAC address. // Possible MAC formats: // 01:23:45:67:89:ab // 01:23:45:67:89:ab:cd:ef // 01-23-45-67-89-ab // 01-23-45-67-89-ab-cd-ef // 0123.4567.89ab // 0123.4567.89ab.cdef func IsMAC(str string) bool { _, err := net.ParseMAC(str) return err == nil } // IsHost checks if the string is a valid IP (both v4 and v6) or a valid DNS name func IsHost(str string) bool { return IsIP(str) || IsDNSName(str) } // IsMongoID checks if the string is a valid hex-encoded representation of a MongoDB ObjectId. func IsMongoID(str string) bool { return rxHexadecimal.MatchString(str) && (len(str) == 24) } // IsLatitude checks if a string is valid latitude. func IsLatitude(str string) bool { return rxLatitude.MatchString(str) } // IsLongitude checks if a string is valid longitude. func IsLongitude(str string) bool { return rxLongitude.MatchString(str) } // IsIMEI checks if a string is valid IMEI func IsIMEI(str string) bool { return rxIMEI.MatchString(str) } // IsIMSI checks if a string is valid IMSI func IsIMSI(str string) bool { if !rxIMSI.MatchString(str) { return false } mcc, err := strconv.ParseInt(str[0:3], 10, 32) if err != nil { return false } switch mcc { case 202, 204, 206, 208, 212, 213, 214, 216, 218, 219: case 220, 221, 222, 226, 228, 230, 231, 232, 234, 235: case 238, 240, 242, 244, 246, 247, 248, 250, 255, 257: case 259, 260, 262, 266, 268, 270, 272, 274, 276, 278: case 280, 282, 283, 284, 286, 288, 289, 290, 292, 293: case 294, 295, 297, 302, 308, 310, 311, 312, 313, 314: case 315, 316, 330, 332, 334, 338, 340, 342, 344, 346: case 348, 350, 352, 354, 356, 358, 360, 362, 363, 364: case 365, 366, 368, 370, 372, 374, 376, 400, 401, 402: case 404, 405, 406, 410, 412, 413, 414, 415, 416, 417: case 418, 419, 420, 421, 422, 424, 425, 426, 427, 428: case 429, 430, 431, 432, 434, 436, 437, 438, 440, 441: case 450, 452, 454, 455, 456, 457, 460, 461, 466, 467: case 470, 472, 502, 505, 510, 514, 515, 520, 525, 528: case 530, 536, 537, 539, 540, 541, 542, 543, 544, 545: case 546, 547, 548, 549, 550, 551, 552, 553, 554, 555: case 602, 603, 604, 605, 606, 607, 608, 609, 610, 611: case 612, 613, 614, 615, 616, 617, 618, 619, 620, 621: case 622, 623, 624, 625, 626, 627, 628, 629, 630, 631: case 632, 633, 634, 635, 636, 637, 638, 639, 640, 641: case 642, 643, 645, 646, 647, 648, 649, 650, 651, 652: case 653, 654, 655, 657, 658, 659, 702, 704, 706, 708: case 710, 712, 714, 716, 722, 724, 730, 732, 734, 736: case 738, 740, 742, 744, 746, 748, 750, 995: return true default: return false } return true } // IsRsaPublicKey checks if a string is valid public key with provided length func IsRsaPublicKey(str string, keylen int) bool { bb := bytes.NewBufferString(str) pemBytes, err := ioutil.ReadAll(bb) if err != nil { return false } block, _ := pem.Decode(pemBytes) if block != nil && block.Type != "PUBLIC KEY" { return false } var der []byte if block != nil { der = block.Bytes } else { der, err = base64.StdEncoding.DecodeString(str) if err != nil { return false } } key, err := x509.ParsePKIXPublicKey(der) if err != nil { return false } pubkey, ok := key.(*rsa.PublicKey) if !ok { return false } bitlen := len(pubkey.N.Bytes()) * 8 return bitlen == int(keylen) } // IsRegex checks if a give string is a valid regex with RE2 syntax or not func IsRegex(str string) bool { if _, err := regexp.Compile(str); err == nil { return true } return false } func toJSONName(tag string) string { if tag == "" { return "" } // JSON name always comes first. If there's no options then split[0] is // JSON name, if JSON name is not set, then split[0] is an empty string. split := strings.SplitN(tag, ",", 2) name := split[0] // However it is possible that the field is skipped when // (de-)serializing from/to JSON, in which case assume that there is no // tag name to use if name == "-" { return "" } return name } func prependPathToErrors(err error, path string) error { switch err2 := err.(type) { case Error: err2.Path = append([]string{path}, err2.Path...) return err2 case Errors: errors := err2.Errors() for i, err3 := range errors { errors[i] = prependPathToErrors(err3, path) } return err2 } return err } // ValidateArray performs validation according to condition iterator that validates every element of the array func ValidateArray(array []interface{}, iterator ConditionIterator) bool { return Every(array, iterator) } // ValidateMap use validation map for fields. // result will be equal to `false` if there are any errors. // s is the map containing the data to be validated. // m is the validation map in the form: // map[string]interface{}{"name":"required,alpha","address":map[string]interface{}{"line1":"required,alphanum"}} func ValidateMap(s map[string]interface{}, m map[string]interface{}) (bool, error) { if s == nil { return true, nil } result := true var err error var errs Errors var index int val := reflect.ValueOf(s) for key, value := range s { presentResult := true validator, ok := m[key] if !ok { presentResult = false var err error err = fmt.Errorf("all map keys has to be present in the validation map; got %s", key) err = prependPathToErrors(err, key) errs = append(errs, err) } valueField := reflect.ValueOf(value) mapResult := true typeResult := true structResult := true resultField := true switch subValidator := validator.(type) { case map[string]interface{}: var err error if v, ok := value.(map[string]interface{}); !ok { mapResult = false err = fmt.Errorf("map validator has to be for the map type only; got %s", valueField.Type().String()) err = prependPathToErrors(err, key) errs = append(errs, err) } else { mapResult, err = ValidateMap(v, subValidator) if err != nil { mapResult = false err = prependPathToErrors(err, key) errs = append(errs, err) } } case string: if (valueField.Kind() == reflect.Struct || (valueField.Kind() == reflect.Ptr && valueField.Elem().Kind() == reflect.Struct)) && subValidator != "-" { var err error structResult, err = ValidateStruct(valueField.Interface()) if err != nil { err = prependPathToErrors(err, key) errs = append(errs, err) } } resultField, err = typeCheck(valueField, reflect.StructField{ Name: key, PkgPath: "", Type: val.Type(), Tag: reflect.StructTag(fmt.Sprintf("%s:%q", tagName, subValidator)), Offset: 0, Index: []int{index}, Anonymous: false, }, val, nil) if err != nil { errs = append(errs, err) } case nil: // already handlerd when checked before default: typeResult = false err = fmt.Errorf("map validator has to be either map[string]interface{} or string; got %s", valueField.Type().String()) err = prependPathToErrors(err, key) errs = append(errs, err) } result = result && presentResult && typeResult && resultField && structResult && mapResult index++ } // checks required keys requiredResult := true for key, value := range m { if schema, ok := value.(string); ok { tags := parseTagIntoMap(schema) if required, ok := tags["required"]; ok { if _, ok := s[key]; !ok { requiredResult = false if required.customErrorMessage != "" { err = Error{key, fmt.Errorf(required.customErrorMessage), true, "required", []string{}} } else { err = Error{key, fmt.Errorf("required field missing"), false, "required", []string{}} } errs = append(errs, err) } } } } if len(errs) > 0 { err = errs } return result && requiredResult, err } // ValidateStruct use tags for fields. // result will be equal to `false` if there are any errors. // todo currently there is no guarantee that errors will be returned in predictable order (tests may to fail) func ValidateStruct(s interface{}) (bool, error) { if s == nil { return true, nil } result := true var err error val := reflect.ValueOf(s) if val.Kind() == reflect.Interface || val.Kind() == reflect.Ptr { val = val.Elem() } // we only accept structs if val.Kind() != reflect.Struct { return false, fmt.Errorf("function only accepts structs; got %s", val.Kind()) } var errs Errors for i := 0; i < val.NumField(); i++ { valueField := val.Field(i) typeField := val.Type().Field(i) if typeField.PkgPath != "" { continue // Private field } structResult := true if valueField.Kind() == reflect.Interface { valueField = valueField.Elem() } if (valueField.Kind() == reflect.Struct || (valueField.Kind() == reflect.Ptr && valueField.Elem().Kind() == reflect.Struct)) && typeField.Tag.Get(tagName) != "-" { var err error structResult, err = ValidateStruct(valueField.Interface()) if err != nil { err = prependPathToErrors(err, typeField.Name) errs = append(errs, err) } } resultField, err2 := typeCheck(valueField, typeField, val, nil) if err2 != nil { // Replace structure name with JSON name if there is a tag on the variable jsonTag := toJSONName(typeField.Tag.Get("json")) if jsonTag != "" { switch jsonError := err2.(type) { case Error: jsonError.Name = jsonTag err2 = jsonError case Errors: for i2, err3 := range jsonError { switch customErr := err3.(type) { case Error: customErr.Name = jsonTag jsonError[i2] = customErr } } err2 = jsonError } } errs = append(errs, err2) } result = result && resultField && structResult } if len(errs) > 0 { err = errs } return result, err } // ValidateStructAsync performs async validation of the struct and returns results through the channels func ValidateStructAsync(s interface{}) (<-chan bool, <-chan error) { res := make(chan bool) errors := make(chan error) go func() { defer close(res) defer close(errors) isValid, isFailed := ValidateStruct(s) res <- isValid errors <- isFailed }() return res, errors } // ValidateMapAsync performs async validation of the map and returns results through the channels func ValidateMapAsync(s map[string]interface{}, m map[string]interface{}) (<-chan bool, <-chan error) { res := make(chan bool) errors := make(chan error) go func() { defer close(res) defer close(errors) isValid, isFailed := ValidateMap(s, m) res <- isValid errors <- isFailed }() return res, errors } // parseTagIntoMap parses a struct tag `valid:required~Some error message,length(2|3)` into map[string]string{"required": "Some error message", "length(2|3)": ""} func parseTagIntoMap(tag string) tagOptionsMap { optionsMap := make(tagOptionsMap) options := strings.Split(tag, ",") for i, option := range options { option = strings.TrimSpace(option) validationOptions := strings.Split(option, "~") if !isValidTag(validationOptions[0]) { continue } if len(validationOptions) == 2 { optionsMap[validationOptions[0]] = tagOption{validationOptions[0], validationOptions[1], i} } else { optionsMap[validationOptions[0]] = tagOption{validationOptions[0], "", i} } } return optionsMap } func isValidTag(s string) bool { if s == "" { return false } for _, c := range s { switch { case strings.ContainsRune("\\'\"!#$%&()*+-./:<=>?@[]^_{|}~ ", c): // Backslash and quote chars are reserved, but // otherwise any punctuation chars are allowed // in a tag name. default: if !unicode.IsLetter(c) && !unicode.IsDigit(c) { return false } } } return true } // IsSSN will validate the given string as a U.S. Social Security Number func IsSSN(str string) bool { if str == "" || len(str) != 11 { return false } return rxSSN.MatchString(str) } // IsSemver checks if string is valid semantic version func IsSemver(str string) bool { return rxSemver.MatchString(str) } // IsType checks if interface is of some type func IsType(v interface{}, params ...string) bool { if len(params) == 1 { typ := params[0] return strings.Replace(reflect.TypeOf(v).String(), " ", "", -1) == strings.Replace(typ, " ", "", -1) } return false } // IsTime checks if string is valid according to given format func IsTime(str string, format string) bool { _, err := time.Parse(format, str) return err == nil } // IsUnixTime checks if string is valid unix timestamp value func IsUnixTime(str string) bool { if _, err := strconv.Atoi(str); err == nil { return true } return false } // IsRFC3339 checks if string is valid timestamp value according to RFC3339 func IsRFC3339(str string) bool { return IsTime(str, time.RFC3339) } // IsRFC3339WithoutZone checks if string is valid timestamp value according to RFC3339 which excludes the timezone. func IsRFC3339WithoutZone(str string) bool { return IsTime(str, rfc3339WithoutZone) } // IsISO4217 checks if string is valid ISO currency code func IsISO4217(str string) bool { for _, currency := range ISO4217List { if str == currency { return true } } return false } // ByteLength checks string's length func ByteLength(str string, params ...string) bool { if len(params) == 2 { min, _ := ToInt(params[0]) max, _ := ToInt(params[1]) return len(str) >= int(min) && len(str) <= int(max) } return false } // RuneLength checks string's length // Alias for StringLength func RuneLength(str string, params ...string) bool { return StringLength(str, params...) } // IsRsaPub checks whether string is valid RSA key // Alias for IsRsaPublicKey func IsRsaPub(str string, params ...string) bool { if len(params) == 1 { len, _ := ToInt(params[0]) return IsRsaPublicKey(str, int(len)) } return false } // StringMatches checks if a string matches a given pattern. func StringMatches(s string, params ...string) bool { if len(params) == 1 { pattern := params[0] return Matches(s, pattern) } return false } // StringLength checks string's length (including multi byte strings) func StringLength(str string, params ...string) bool { if len(params) == 2 { strLength := utf8.RuneCountInString(str) min, _ := ToInt(params[0]) max, _ := ToInt(params[1]) return strLength >= int(min) && strLength <= int(max) } return false } // MinStringLength checks string's minimum length (including multi byte strings) func MinStringLength(str string, params ...string) bool { if len(params) == 1 { strLength := utf8.RuneCountInString(str) min, _ := ToInt(params[0]) return strLength >= int(min) } return false } // MaxStringLength checks string's maximum length (including multi byte strings) func MaxStringLength(str string, params ...string) bool { if len(params) == 1 { strLength := utf8.RuneCountInString(str) max, _ := ToInt(params[0]) return strLength <= int(max) } return false } // Range checks string's length func Range(str string, params ...string) bool { if len(params) == 2 { value, _ := ToFloat(str) min, _ := ToFloat(params[0]) max, _ := ToFloat(params[1]) return InRange(value, min, max) } return false } // IsInRaw checks if string is in list of allowed values func IsInRaw(str string, params ...string) bool { if len(params) == 1 { rawParams := params[0] parsedParams := strings.Split(rawParams, "|") return IsIn(str, parsedParams...) } return false } // IsIn checks if string str is a member of the set of strings params func IsIn(str string, params ...string) bool { for _, param := range params { if str == param { return true } } return false } func checkRequired(v reflect.Value, t reflect.StructField, options tagOptionsMap) (bool, error) { if nilPtrAllowedByRequired { k := v.Kind() if (k == reflect.Ptr || k == reflect.Interface) && v.IsNil() { return true, nil } } if requiredOption, isRequired := options["required"]; isRequired { if len(requiredOption.customErrorMessage) > 0 { return false, Error{t.Name, fmt.Errorf(requiredOption.customErrorMessage), true, "required", []string{}} } return false, Error{t.Name, fmt.Errorf("non zero value required"), false, "required", []string{}} } else if _, isOptional := options["optional"]; fieldsRequiredByDefault && !isOptional { return false, Error{t.Name, fmt.Errorf("Missing required field"), false, "required", []string{}} } // not required and empty is valid return true, nil } func typeCheck(v reflect.Value, t reflect.StructField, o reflect.Value, options tagOptionsMap) (isValid bool, resultErr error) { if !v.IsValid() { return false, nil } tag := t.Tag.Get(tagName) // checks if the field should be ignored switch tag { case "": if v.Kind() != reflect.Slice && v.Kind() != reflect.Map { if !fieldsRequiredByDefault { return true, nil } return false, Error{t.Name, fmt.Errorf("All fields are required to at least have one validation defined"), false, "required", []string{}} } case "-": return true, nil } isRootType := false if options == nil { isRootType = true options = parseTagIntoMap(tag) } if isEmptyValue(v) { // an empty value is not validated, checks only required isValid, resultErr = checkRequired(v, t, options) for key := range options { delete(options, key) } return isValid, resultErr } var customTypeErrors Errors optionsOrder := options.orderedKeys() for _, validatorName := range optionsOrder { validatorStruct := options[validatorName] if validatefunc, ok := CustomTypeTagMap.Get(validatorName); ok { delete(options, validatorName) if result := validatefunc(v.Interface(), o.Interface()); !result { if len(validatorStruct.customErrorMessage) > 0 { customTypeErrors = append(customTypeErrors, Error{Name: t.Name, Err: TruncatingErrorf(validatorStruct.customErrorMessage, fmt.Sprint(v), validatorName), CustomErrorMessageExists: true, Validator: stripParams(validatorName)}) continue } customTypeErrors = append(customTypeErrors, Error{Name: t.Name, Err: fmt.Errorf("%s does not validate as %s", fmt.Sprint(v), validatorName), CustomErrorMessageExists: false, Validator: stripParams(validatorName)}) } } } if len(customTypeErrors.Errors()) > 0 { return false, customTypeErrors } if isRootType { // Ensure that we've checked the value by all specified validators before report that the value is valid defer func() { delete(options, "optional") delete(options, "required") if isValid && resultErr == nil && len(options) != 0 { optionsOrder := options.orderedKeys() for _, validator := range optionsOrder { isValid = false resultErr = Error{t.Name, fmt.Errorf( "The following validator is invalid or can't be applied to the field: %q", validator), false, stripParams(validator), []string{}} return } } }() } for _, validatorSpec := range optionsOrder { validatorStruct := options[validatorSpec] var negate bool validator := validatorSpec customMsgExists := len(validatorStruct.customErrorMessage) > 0 // checks whether the tag looks like '!something' or 'something' if validator[0] == '!' { validator = validator[1:] negate = true } // checks for interface param validators for key, value := range InterfaceParamTagRegexMap { ps := value.FindStringSubmatch(validator) if len(ps) == 0 { continue } validatefunc, ok := InterfaceParamTagMap[key] if !ok { continue } delete(options, validatorSpec) field := fmt.Sprint(v) if result := validatefunc(v.Interface(), ps[1:]...); (!result && !negate) || (result && negate) { if customMsgExists { return false, Error{t.Name, TruncatingErrorf(validatorStruct.customErrorMessage, field, validator), customMsgExists, stripParams(validatorSpec), []string{}} } if negate { return false, Error{t.Name, fmt.Errorf("%s does validate as %s", field, validator), customMsgExists, stripParams(validatorSpec), []string{}} } return false, Error{t.Name, fmt.Errorf("%s does not validate as %s", field, validator), customMsgExists, stripParams(validatorSpec), []string{}} } } } switch v.Kind() { case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.Float32, reflect.Float64, reflect.String: // for each tag option checks the map of validator functions for _, validatorSpec := range optionsOrder { validatorStruct := options[validatorSpec] var negate bool validator := validatorSpec customMsgExists := len(validatorStruct.customErrorMessage) > 0 // checks whether the tag looks like '!something' or 'something' if validator[0] == '!' { validator = validator[1:] negate = true } // checks for param validators for key, value := range ParamTagRegexMap { ps := value.FindStringSubmatch(validator) if len(ps) == 0 { continue } validatefunc, ok := ParamTagMap[key] if !ok { continue } delete(options, validatorSpec) switch v.Kind() { case reflect.String, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64: field := fmt.Sprint(v) // make value into string, then validate with regex if result := validatefunc(field, ps[1:]...); (!result && !negate) || (result && negate) { if customMsgExists { return false, Error{t.Name, TruncatingErrorf(validatorStruct.customErrorMessage, field, validator), customMsgExists, stripParams(validatorSpec), []string{}} } if negate { return false, Error{t.Name, fmt.Errorf("%s does validate as %s", field, validator), customMsgExists, stripParams(validatorSpec), []string{}} } return false, Error{t.Name, fmt.Errorf("%s does not validate as %s", field, validator), customMsgExists, stripParams(validatorSpec), []string{}} } default: // type not yet supported, fail return false, Error{t.Name, fmt.Errorf("Validator %s doesn't support kind %s", validator, v.Kind()), false, stripParams(validatorSpec), []string{}} } } if validatefunc, ok := TagMap[validator]; ok { delete(options, validatorSpec) switch v.Kind() { case reflect.String, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64: field := fmt.Sprint(v) // make value into string, then validate with regex if result := validatefunc(field); !result && !negate || result && negate { if customMsgExists { return false, Error{t.Name, TruncatingErrorf(validatorStruct.customErrorMessage, field, validator), customMsgExists, stripParams(validatorSpec), []string{}} } if negate { return false, Error{t.Name, fmt.Errorf("%s does validate as %s", field, validator), customMsgExists, stripParams(validatorSpec), []string{}} } return false, Error{t.Name, fmt.Errorf("%s does not validate as %s", field, validator), customMsgExists, stripParams(validatorSpec), []string{}} } default: //Not Yet Supported Types (Fail here!) err := fmt.Errorf("Validator %s doesn't support kind %s for value %v", validator, v.Kind(), v) return false, Error{t.Name, err, false, stripParams(validatorSpec), []string{}} } } } return true, nil case reflect.Map: if v.Type().Key().Kind() != reflect.String { return false, &UnsupportedTypeError{v.Type()} } var sv stringValues sv = v.MapKeys() sort.Sort(sv) result := true for i, k := range sv { var resultItem bool var err error if v.MapIndex(k).Kind() != reflect.Struct { resultItem, err = typeCheck(v.MapIndex(k), t, o, options) if err != nil { return false, err } } else { resultItem, err = ValidateStruct(v.MapIndex(k).Interface()) if err != nil { err = prependPathToErrors(err, t.Name+"."+sv[i].Interface().(string)) return false, err } } result = result && resultItem } return result, nil case reflect.Slice, reflect.Array: result := true for i := 0; i < v.Len(); i++ { var resultItem bool var err error if v.Index(i).Kind() != reflect.Struct { resultItem, err = typeCheck(v.Index(i), t, o, options) if err != nil { return false, err } } else { resultItem, err = ValidateStruct(v.Index(i).Interface()) if err != nil { err = prependPathToErrors(err, t.Name+"."+strconv.Itoa(i)) return false, err } } result = result && resultItem } return result, nil case reflect.Interface: // If the value is an interface then encode its element if v.IsNil() { return true, nil } return ValidateStruct(v.Interface()) case reflect.Ptr: // If the value is a pointer then checks its element if v.IsNil() { return true, nil } return typeCheck(v.Elem(), t, o, options) case reflect.Struct: return true, nil default: return false, &UnsupportedTypeError{v.Type()} } } func stripParams(validatorString string) string { return paramsRegexp.ReplaceAllString(validatorString, "") } // isEmptyValue checks whether value empty or not func isEmptyValue(v reflect.Value) bool { switch v.Kind() { case reflect.String, reflect.Array: return v.Len() == 0 case reflect.Map, reflect.Slice: return v.Len() == 0 || v.IsNil() case reflect.Bool: return !v.Bool() case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return v.Int() == 0 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return v.Uint() == 0 case reflect.Float32, reflect.Float64: return v.Float() == 0 case reflect.Interface, reflect.Ptr: return v.IsNil() } return reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface()) } // ErrorByField returns error for specified field of the struct // validated by ValidateStruct or empty string if there are no errors // or this field doesn't exists or doesn't have any errors. func ErrorByField(e error, field string) string { if e == nil { return "" } return ErrorsByField(e)[field] } // ErrorsByField returns map of errors of the struct validated // by ValidateStruct or empty map if there are no errors. func ErrorsByField(e error) map[string]string { m := make(map[string]string) if e == nil { return m } // prototype for ValidateStruct switch e := e.(type) { case Error: m[e.Name] = e.Err.Error() case Errors: for _, item := range e.Errors() { n := ErrorsByField(item) for k, v := range n { m[k] = v } } } return m } // Error returns string equivalent for reflect.Type func (e *UnsupportedTypeError) Error() string { return "validator: unsupported type: " + e.Type.String() } func (sv stringValues) Len() int { return len(sv) } func (sv stringValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] } func (sv stringValues) Less(i, j int) bool { return sv.get(i) < sv.get(j) } func (sv stringValues) get(i int) string { return sv[i].String() } func IsE164(str string) bool { return rxE164.MatchString(str) } govalidator-11.0.1/validator_test.go000066400000000000000000003076511402110523600174660ustar00rootroot00000000000000package govalidator import ( "fmt" "strings" "testing" "time" ) func init() { CustomTypeTagMap.Set("customFalseValidator", CustomTypeValidator(func(i interface{}, o interface{}) bool { return false })) CustomTypeTagMap.Set("customTrueValidator", CustomTypeValidator(func(i interface{}, o interface{}) bool { return true })) } func TestIsAlpha(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"\n", false}, {"\r", false}, {"Ⅸ", false}, {"", true}, {" fooo ", false}, {"abc!!!", false}, {"abc1", false}, {"abc〩", false}, {"abc", true}, {"소주", false}, {"ABC", true}, {"FoObAr", true}, {"소aBC", false}, {"소", false}, {"달기&Co.", false}, {"〩Hours", false}, {"\ufff0", false}, {"\u0070", true}, //UTF-8(ASCII): p {"\u0026", false}, //UTF-8(ASCII): & {"\u0030", false}, //UTF-8(ASCII): 0 {"123", false}, {"0123", false}, {"-00123", false}, {"0", false}, {"-0", false}, {"123.123", false}, {" ", false}, {".", false}, {"-1¾", false}, {"1¾", false}, {"〥〩", false}, {"모자", false}, {"ix", true}, {"۳۵۶۰", false}, {"1--", false}, {"1-1", false}, {"-", false}, {"--", false}, {"1++", false}, {"1+1", false}, {"+", false}, {"++", false}, {"+1", false}, } for _, test := range tests { actual := IsAlpha(test.param) if actual != test.expected { t.Errorf("Expected IsAlpha(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsUTFLetter(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"\n", false}, {"\r", false}, {"Ⅸ", false}, {"", true}, {" fooo ", false}, {"abc!!!", false}, {"abc1", false}, {"abc〩", false}, {"", true}, {"abc", true}, {"소주", true}, {"ABC", true}, {"FoObAr", true}, {"소aBC", true}, {"소", true}, {"달기&Co.", false}, {"〩Hours", false}, {"\ufff0", false}, {"\u0070", true}, //UTF-8(ASCII): p {"\u0026", false}, //UTF-8(ASCII): & {"\u0030", false}, //UTF-8(ASCII): 0 {"123", false}, {"0123", false}, {"-00123", false}, {"0", false}, {"-0", false}, {"123.123", false}, {" ", false}, {".", false}, {"-1¾", false}, {"1¾", false}, {"〥〩", false}, {"모자", true}, {"ix", true}, {"۳۵۶۰", false}, {"1--", false}, {"1-1", false}, {"-", false}, {"--", false}, {"1++", false}, {"1+1", false}, {"+", false}, {"++", false}, {"+1", false}, } for _, test := range tests { actual := IsUTFLetter(test.param) if actual != test.expected { t.Errorf("Expected IsUTFLetter(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsAlphanumeric(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"\n", false}, {"\r", false}, {"Ⅸ", false}, {"", true}, {" fooo ", false}, {"abc!!!", false}, {"abc123", true}, {"ABC111", true}, {"abc1", true}, {"abc〩", false}, {"abc", true}, {"소주", false}, {"ABC", true}, {"FoObAr", true}, {"소aBC", false}, {"소", false}, {"달기&Co.", false}, {"〩Hours", false}, {"\ufff0", false}, {"\u0070", true}, //UTF-8(ASCII): p {"\u0026", false}, //UTF-8(ASCII): & {"\u0030", true}, //UTF-8(ASCII): 0 {"123", true}, {"0123", true}, {"-00123", false}, {"0", true}, {"-0", false}, {"123.123", false}, {" ", false}, {".", false}, {"-1¾", false}, {"1¾", false}, {"〥〩", false}, {"모자", false}, {"ix", true}, {"۳۵۶۰", false}, {"1--", false}, {"1-1", false}, {"-", false}, {"--", false}, {"1++", false}, {"1+1", false}, {"+", false}, {"++", false}, {"+1", false}, } for _, test := range tests { actual := IsAlphanumeric(test.param) if actual != test.expected { t.Errorf("Expected IsAlphanumeric(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsUTFLetterNumeric(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"\n", false}, {"\r", false}, {"Ⅸ", true}, {"", true}, {" fooo ", false}, {"abc!!!", false}, {"abc1", true}, {"abc〩", true}, {"abc", true}, {"소주", true}, {"ABC", true}, {"FoObAr", true}, {"소aBC", true}, {"소", true}, {"달기&Co.", false}, {"〩Hours", true}, {"\ufff0", false}, {"\u0070", true}, //UTF-8(ASCII): p {"\u0026", false}, //UTF-8(ASCII): & {"\u0030", true}, //UTF-8(ASCII): 0 {"123", true}, {"0123", true}, {"-00123", false}, {"0", true}, {"-0", false}, {"123.123", false}, {" ", false}, {".", false}, {"-1¾", false}, {"1¾", true}, {"〥〩", true}, {"모자", true}, {"ix", true}, {"۳۵۶۰", true}, {"1--", false}, {"1-1", false}, {"-", false}, {"--", false}, {"1++", false}, {"1+1", false}, {"+", false}, {"++", false}, {"+1", false}, } for _, test := range tests { actual := IsUTFLetterNumeric(test.param) if actual != test.expected { t.Errorf("Expected IsUTFLetterNumeric(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsNumeric(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"\n", false}, {"\r", false}, {"Ⅸ", false}, {"", true}, {" fooo ", false}, {"abc!!!", false}, {"abc1", false}, {"abc〩", false}, {"abc", false}, {"소주", false}, {"ABC", false}, {"FoObAr", false}, {"소aBC", false}, {"소", false}, {"달기&Co.", false}, {"〩Hours", false}, {"\ufff0", false}, {"\u0070", false}, //UTF-8(ASCII): p {"\u0026", false}, //UTF-8(ASCII): & {"\u0030", true}, //UTF-8(ASCII): 0 {"123", true}, {"0123", true}, {"-00123", false}, {"+00123", false}, {"0", true}, {"-0", false}, {"123.123", false}, {" ", false}, {".", false}, {"12𐅪3", false}, {"-1¾", false}, {"1¾", false}, {"〥〩", false}, {"모자", false}, {"ix", false}, {"۳۵۶۰", false}, {"1--", false}, {"1-1", false}, {"-", false}, {"--", false}, {"1++", false}, {"1+1", false}, {"+", false}, {"++", false}, {"+1", false}, } for _, test := range tests { actual := IsNumeric(test.param) if actual != test.expected { t.Errorf("Expected IsNumeric(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsUTFNumeric(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"\n", false}, {"\r", false}, {"Ⅸ", true}, {"", true}, {" fooo ", false}, {"abc!!!", false}, {"abc1", false}, {"abc〩", false}, {"abc", false}, {"소주", false}, {"ABC", false}, {"FoObAr", false}, {"소aBC", false}, {"소", false}, {"달기&Co.", false}, {"〩Hours", false}, {"\ufff0", false}, {"\u0070", false}, //UTF-8(ASCII): p {"\u0026", false}, //UTF-8(ASCII): & {"\u0030", true}, //UTF-8(ASCII): 0 {"123", true}, {"0123", true}, {"-00123", true}, {"0", true}, {"-0", true}, {"--0", false}, {"-0-", false}, {"123.123", false}, {" ", false}, {".", false}, {"12𐅪3", true}, {"-1¾", true}, {"1¾", true}, {"〥〩", true}, {"모자", false}, {"ix", false}, {"۳۵۶۰", true}, {"1++", false}, {"1+1", false}, {"+", false}, {"++", false}, {"+1", true}, } for _, test := range tests { actual := IsUTFNumeric(test.param) if actual != test.expected { t.Errorf("Expected IsUTFNumeric(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsUTFDigit(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"\n", false}, {"\r", false}, {"Ⅸ", false}, {"", true}, {" fooo ", false}, {"abc!!!", false}, {"abc1", false}, {"abc〩", false}, {"abc", false}, {"소주", false}, {"ABC", false}, {"FoObAr", false}, {"소aBC", false}, {"소", false}, {"달기&Co.", false}, {"〩Hours", false}, {"\ufff0", false}, {"\u0070", false}, //UTF-8(ASCII): p {"\u0026", false}, //UTF-8(ASCII): & {"\u0030", true}, //UTF-8(ASCII): 0 {"123", true}, {"0123", true}, {"-00123", true}, {"0", true}, {"-0", true}, {"--0", false}, {"-0-", false}, {"123.123", false}, {" ", false}, {".", false}, {"12𐅪3", false}, {"1483920", true}, {"", true}, {"۳۵۶۰", true}, {"-29", true}, {"-1¾", false}, {"1¾", false}, {"〥〩", false}, {"모자", false}, {"ix", false}, {"۳۵۶۰", true}, {"1++", false}, {"1+1", false}, {"+", false}, {"++", false}, {"+1", true}, } for _, test := range tests { actual := IsUTFDigit(test.param) if actual != test.expected { t.Errorf("Expected IsUTFDigit(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsLowerCase(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"", true}, {"abc123", true}, {"abc", true}, {"a b c", true}, {"abcß", true}, {"abcẞ", false}, {"ABCẞ", false}, {"tr竪s 端ber", true}, {"fooBar", false}, {"123ABC", false}, {"ABC123", false}, {"ABC", false}, {"S T R", false}, {"fooBar", false}, {"abacaba123", true}, } for _, test := range tests { actual := IsLowerCase(test.param) if actual != test.expected { t.Errorf("Expected IsLowerCase(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsUpperCase(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"", true}, {"abc123", false}, {"abc", false}, {"a b c", false}, {"abcß", false}, {"abcẞ", false}, {"ABCẞ", true}, {"tr竪s 端ber", false}, {"fooBar", false}, {"123ABC", true}, {"ABC123", true}, {"ABC", true}, {"S T R", true}, {"fooBar", false}, {"abacaba123", false}, } for _, test := range tests { actual := IsUpperCase(test.param) if actual != test.expected { t.Errorf("Expected IsUpperCase(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestHasLowerCase(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"", true}, {"abc123", true}, {"abc", true}, {"a b c", true}, {"abcß", true}, {"abcẞ", true}, {"ABCẞ", false}, {"tr竪s 端ber", true}, {"fooBar", true}, {"123ABC", false}, {"ABC123", false}, {"ABC", false}, {"S T R", false}, {"fooBar", true}, {"abacaba123", true}, {"FÒÔBÀŘ", false}, {"fòôbàř", true}, {"fÒÔBÀŘ", true}, } for _, test := range tests { actual := HasLowerCase(test.param) if actual != test.expected { t.Errorf("Expected HasLowerCase(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestHasUpperCase(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"", true}, {"abc123", false}, {"abc", false}, {"a b c", false}, {"abcß", false}, {"abcẞ", false}, {"ABCẞ", true}, {"tr竪s 端ber", false}, {"fooBar", true}, {"123ABC", true}, {"ABC123", true}, {"ABC", true}, {"S T R", true}, {"fooBar", true}, {"abacaba123", false}, {"FÒÔBÀŘ", true}, {"fòôbàř", false}, {"Fòôbàř", true}, } for _, test := range tests { actual := HasUpperCase(test.param) if actual != test.expected { t.Errorf("Expected HasUpperCase(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsInt(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"-2147483648", true}, //Signed 32 Bit Min Int {"2147483647", true}, //Signed 32 Bit Max Int {"-2147483649", true}, //Signed 32 Bit Min Int - 1 {"2147483648", true}, //Signed 32 Bit Max Int + 1 {"4294967295", true}, //Unsigned 32 Bit Max Int {"4294967296", true}, //Unsigned 32 Bit Max Int + 1 {"-9223372036854775808", true}, //Signed 64 Bit Min Int {"9223372036854775807", true}, //Signed 64 Bit Max Int {"-9223372036854775809", true}, //Signed 64 Bit Min Int - 1 {"9223372036854775808", true}, //Signed 64 Bit Max Int + 1 {"18446744073709551615", true}, //Unsigned 64 Bit Max Int {"18446744073709551616", true}, //Unsigned 64 Bit Max Int + 1 {"", true}, {"123", true}, {"0", true}, {"-0", true}, {"+0", true}, {"01", false}, {"123.123", false}, {" ", false}, {"000", false}, } for _, test := range tests { actual := IsInt(test.param) if actual != test.expected { t.Errorf("Expected IsInt(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsHash(t *testing.T) { t.Parallel() var tests = []struct { param string algo string expected bool }{ {"3ca25ae354e192b26879f651a51d92aa8a34d8d3", "sha1", true}, {"3ca25ae354e192b26879f651a51d34d8d3", "sha1", false}, {"3ca25ae354e192b26879f651a51d92aa8a34d8d3", "Tiger160", true}, {"3ca25ae354e192b26879f651a51d34d8d3", "ripemd160", false}, {"579282cfb65ca1f109b78536effaf621b853c9f7079664a3fbe2b519f435898c", "sha256", true}, {"579282cfb65ca1f109b78536effaf621b853c9f7079664a3fbe2b519f435898casfdsafsadfsdf", "sha256", false}, {"bf547c3fc5841a377eb1519c2890344dbab15c40ae4150b4b34443d2212e5b04aa9d58865bf03d8ae27840fef430b891", "sha384", true}, {"579282cfb65ca1f109b78536effaf621b853c9f7079664a3fbe2b519f435898casfdsafsadfsdf", "sha384", false}, {"45bc5fa8cb45ee408c04b6269e9f1e1c17090c5ce26ffeeda2af097735b29953ce547e40ff3ad0d120e5361cc5f9cee35ea91ecd4077f3f589b4d439168f91b9", "sha512", true}, {"579282cfb65ca1f109b78536effaf621b853c9f7079664a3fbe2b519f435898casfdsafsadfsdf", "sha512", false}, {"46fc0125a148788a3ac1d649566fc04eb84a746f1a6e4fa7", "tiger192", true}, {"46fc0125a148788a3ac1d649566fc04eb84a746f1a6$$%@^", "TIGER192", false}, {"46fc0125a148788a3ac1d649566fc04eb84a746f1a6$$%@^", "SOMEHASH", false}, {"b87f88c72702fff1748e58b87e9141a42c0dbedc29a78cb0d4a5cd81", "sha3-224", true}, {"b87f88c72702fff1748e58b87e9141a42c0dbedc29a78cb0d4a5cd81g", "sha3-224", false}, {"3338be694f50c5f338814986cdf0686453a888b84f424d792af4b9202398f392", "sha3-256", true}, {"3338be694f50c5f338814986cdf0686453a888b84f424d792af4b9202398f392g", "sha3-256", false}, {"720aea11019ef06440fbf05d87aa24680a2153df3907b23631e7177ce620fa1330ff07c0fddee54699a4c3ee0ee9d887", "sha3-384", true}, {"720aea11019ef06440fbf05d87aa24680a2153df3907b23631e7177ce620fa1330ff07c0fddee54699a4c3ee0ee9d88", "sha3-384", false}, {"75d527c368f2efe848ecf6b073a36767800805e9eef2b1857d5f984f036eb6df891d75f72d9b154518c1cd58835286d1da9a38deba3de98b5a53e5ed78a84976", "sha3-512", true}, {"75d527c368f2efe848ecf6b073a36767800805e9eef2b1857d5f984f036eb6df891d75f72d9b154518c1cd58835286d1da9a38deba3de98b5a53e5ed78a8497", "sha3-512", false}, } for _, test := range tests { actual := IsHash(test.param, test.algo) if actual != test.expected { t.Errorf("Expected IsHash(%q, %q) to be %v, got %v", test.param, test.algo, test.expected, actual) } } } func TestIsSHA3224(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"b87f88c72702fff1748e58b87e9141a42c0dbedc29a78cb0d4a5cd81", true}, {"b87f88c72702fff1748e58b87e9141a42c0dbedc29a78cb0d4a5cd81g", false}, } for _, test := range tests { actual := IsSHA3224(test.param) if actual != test.expected { t.Errorf("Expected IsSHA3224(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsSHA3256(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"3338be694f50c5f338814986cdf0686453a888b84f424d792af4b9202398f392", true}, {"3338be694f50c5f338814986cdf0686453a888b84f424d792af4b9202398f39", false}, } for _, test := range tests { actual := IsSHA3256(test.param) if actual != test.expected { t.Errorf("Expected IsSHA3256(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsSHA3384(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"720aea11019ef06440fbf05d87aa24680a2153df3907b23631e7177ce620fa1330ff07c0fddee54699a4c3ee0ee9d887", true}, {"720aea11019ef06440fbf05d87aa24680a2153df3907b23631e7177ce620fa1330ff07c0fddee54699a4c3ee0ee9d88", false}, } for _, test := range tests { actual := IsSHA3384(test.param) if actual != test.expected { t.Errorf("Expected IsSHA3384(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsSHA3512(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"75d527c368f2efe848ecf6b073a36767800805e9eef2b1857d5f984f036eb6df891d75f72d9b154518c1cd58835286d1da9a38deba3de98b5a53e5ed78a84976", true}, {"75d527c368f2efe848ecf6b073a36767800805e9eef2b1857d5f984f036eb6df891d75f72d9b154518c1cd58835286d1da9a38deba3de98b5a53e5ed78a8497", false}, } for _, test := range tests { actual := IsSHA3512(test.param) if actual != test.expected { t.Errorf("Expected IsSHA3512(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsExistingEmail(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"", false}, {"foo@bar.com", true}, {"foo@bar.com.au", true}, {"foo+bar@bar.com", true}, {"foo@bar.coffee..coffee", false}, {"invalidemail@", false}, {"invalid.com", false}, {"@invalid.com", false}, {"NathAn.daVIeS@DomaIn.cOM", true}, {"NATHAN.DAVIES@DOMAIN.CO.UK", true}, {"prasun.joshi@localhost", true}, {"[prasun.joshi]@DomaIn.cOM", false}, {"sizeofuserismorethansixtyfour0123sizeofuserismorethansixtyfour0123@DOMAIN.CO.UK", false}, {"nosuchdomain@bar.nosuchdomainsuffix", false}, } for _, test := range tests { actual := IsExistingEmail(test.param) if actual != test.expected { t.Errorf("Expected IsExistingEmail(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsEmail(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"", false}, {"foo@bar.com", true}, {"x@x.x", true}, {"foo@bar.com.au", true}, {"foo+bar@bar.com", true}, {"foo@bar.coffee", true}, {"foo@bar.coffee..coffee", false}, {"foo@bar.bar.coffee", true}, {"foo@bar.中文网", true}, {"invalidemail@", false}, {"invalid.com", false}, {"@invalid.com", false}, {"test|123@m端ller.com", true}, {"hans@m端ller.com", true}, {"hans.m端ller@test.com", true}, {"NathAn.daVIeS@DomaIn.cOM", true}, {"NATHAN.DAVIES@DOMAIN.CO.UK", true}, } for _, test := range tests { actual := IsEmail(test.param) if actual != test.expected { t.Errorf("Expected IsEmail(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsURL(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"", false}, {"http://foo.bar#com", true}, {"http://foobar.com", true}, {"https://foobar.com", true}, {"foobar.com", true}, {"http://foobar.coffee/", true}, {"http://foobar.中文网/", true}, {"http://foobar.org/", true}, {"http://foobar.ORG", true}, {"http://foobar.org:8080/", true}, {"ftp://foobar.ru/", true}, {"ftp.foo.bar", true}, {"http://user:pass@www.foobar.com/", true}, {"http://user:pass@www.foobar.com/path/file", true}, {"http://127.0.0.1/", true}, {"http://duckduckgo.com/?q=%2F", true}, {"http://localhost:3000/", true}, {"http://foobar.com/?foo=bar#baz=qux", true}, {"http://foobar.com?foo=bar", true}, {"http://www.xn--froschgrn-x9a.net/", true}, {"http://foobar.com/a-", true}, {"http://foobar.پاکستان/", true}, {"http://foobar.c_o_m", false}, {"http://_foobar.com", false}, {"http://foo_bar.com", true}, {"http://user:pass@foo_bar_bar.bar_foo.com", true}, {"", false}, {"xyz://foobar.com", false}, // {"invalid.", false}, is it false like "localhost."? {".com", false}, {"rtmp://foobar.com", false}, {"http://localhost:3000/", true}, {"http://foobar.com#baz=qux", true}, {"http://foobar.com/t$-_.+!*\\'(),", true}, {"http://www.foobar.com/~foobar", true}, {"http://www.-foobar.com/", false}, {"http://www.foo---bar.com/", false}, {"http://r6---snnvoxuioq6.googlevideo.com", true}, {"mailto:someone@example.com", true}, {"irc://irc.server.org/channel", false}, {"irc://#channel@network", true}, {"/abs/test/dir", false}, {"./rel/test/dir", false}, {"http://foo^bar.org", false}, {"http://foo&*bar.org", false}, {"http://foo&bar.org", false}, {"http://foo bar.org", false}, {"http://foo.bar.org", true}, {"http://www.foo.bar.org", true}, {"http://www.foo.co.uk", true}, {"foo", false}, {"http://.foo.com", false}, {"http://,foo.com", false}, {",foo.com", false}, {"http://myservice.:9093/", true}, // according to issues #62 #66 {"https://pbs.twimg.com/profile_images/560826135676588032/j8fWrmYY_normal.jpeg", true}, // according to #125 {"http://prometheus-alertmanager.service.q:9093", true}, {"aio1_alertmanager_container-63376c45:9093", true}, {"https://www.logn-123-123.url.with.sigle.letter.d:12345/url/path/foo?bar=zzz#user", true}, {"http://me.example.com", true}, {"http://www.me.example.com", true}, {"https://farm6.static.flickr.com", true}, {"https://zh.wikipedia.org/wiki/Wikipedia:%E9%A6%96%E9%A1%B5", true}, {"google", false}, // According to #87 {"http://hyphenated-host-name.example.co.in", true}, {"http://cant-end-with-hyphen-.example.com", false}, {"http://-cant-start-with-hyphen.example.com", false}, {"http://www.domain-can-have-dashes.com", true}, {"http://m.abcd.com/test.html", true}, {"http://m.abcd.com/a/b/c/d/test.html?args=a&b=c", true}, {"http://[::1]:9093", true}, {"http://[::1]:909388", false}, {"1200::AB00:1234::2552:7777:1313", false}, {"http://[2001:db8:a0b:12f0::1]/index.html", true}, {"http://[1200:0000:AB00:1234:0000:2552:7777:1313]", true}, {"http://user:pass@[::1]:9093/a/b/c/?a=v#abc", true}, {"https://127.0.0.1/a/b/c?a=v&c=11d", true}, {"https://foo_bar.example.com", true}, {"http://foo_bar.example.com", true}, {"http://foo_bar_fizz_buzz.example.com", true}, {"http://_cant_start_with_underescore", false}, {"http://cant_end_with_underescore_", false}, {"foo_bar.example.com", true}, {"foo_bar_fizz_buzz.example.com", true}, {"http://hello_world.example.com", true}, // According to #212 {"foo_bar-fizz-buzz:1313", true}, {"foo_bar-fizz-buzz:13:13", false}, {"foo_bar-fizz-buzz://1313", false}, } for _, test := range tests { actual := IsURL(test.param) if actual != test.expected { t.Errorf("Expected IsURL(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsRequestURL(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"", false}, {"http://foo.bar/#com", true}, {"http://foobar.com", true}, {"https://foobar.com", true}, {"foobar.com", false}, {"http://foobar.coffee/", true}, {"http://foobar.中文网/", true}, {"http://foobar.org/", true}, {"http://foobar.org:8080/", true}, {"ftp://foobar.ru/", true}, {"http://user:pass@www.foobar.com/", true}, {"http://127.0.0.1/", true}, {"http://duckduckgo.com/?q=%2F", true}, {"http://localhost:3000/", true}, {"http://foobar.com/?foo=bar#baz=qux", true}, {"http://foobar.com?foo=bar", true}, {"http://www.xn--froschgrn-x9a.net/", true}, {"", false}, {"xyz://foobar.com", true}, {"invalid.", false}, {".com", false}, {"rtmp://foobar.com", true}, {"http://www.foo_bar.com/", true}, {"http://localhost:3000/", true}, {"http://foobar.com/#baz=qux", true}, {"http://foobar.com/t$-_.+!*\\'(),", true}, {"http://www.foobar.com/~foobar", true}, {"http://www.-foobar.com/", true}, {"http://www.foo---bar.com/", true}, {"mailto:someone@example.com", true}, {"irc://irc.server.org/channel", true}, {"/abs/test/dir", false}, {"./rel/test/dir", false}, } for _, test := range tests { actual := IsRequestURL(test.param) if actual != test.expected { t.Errorf("Expected IsRequestURL(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsRequestURI(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"", false}, {"http://foo.bar/#com", true}, {"http://foobar.com", true}, {"https://foobar.com", true}, {"foobar.com", false}, {"http://foobar.coffee/", true}, {"http://foobar.中文网/", true}, {"http://foobar.org/", true}, {"http://foobar.org:8080/", true}, {"ftp://foobar.ru/", true}, {"http://user:pass@www.foobar.com/", true}, {"http://127.0.0.1/", true}, {"http://duckduckgo.com/?q=%2F", true}, {"http://localhost:3000/", true}, {"http://foobar.com/?foo=bar#baz=qux", true}, {"http://foobar.com?foo=bar", true}, {"http://www.xn--froschgrn-x9a.net/", true}, {"xyz://foobar.com", true}, {"invalid.", false}, {".com", false}, {"rtmp://foobar.com", true}, {"http://www.foo_bar.com/", true}, {"http://localhost:3000/", true}, {"http://foobar.com/#baz=qux", true}, {"http://foobar.com/t$-_.+!*\\'(),", true}, {"http://www.foobar.com/~foobar", true}, {"http://www.-foobar.com/", true}, {"http://www.foo---bar.com/", true}, {"mailto:someone@example.com", true}, {"irc://irc.server.org/channel", true}, {"/abs/test/dir", true}, {"./rel/test/dir", false}, } for _, test := range tests { actual := IsRequestURI(test.param) if actual != test.expected { t.Errorf("Expected IsRequestURI(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsFloat(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"", false}, {" ", false}, {"-.123", false}, {"abacaba", false}, {"1f", false}, {"-1f", false}, {"+1f", false}, {"123", true}, {"123.", true}, {"123.123", true}, {"-123.123", true}, {"+123.123", true}, {"0.123", true}, {"-0.123", true}, {"+0.123", true}, {".0", true}, {"01.123", true}, {"-0.22250738585072011e-307", true}, {"+0.22250738585072011e-307", true}, } for _, test := range tests { actual := IsFloat(test.param) if actual != test.expected { t.Errorf("Expected IsFloat(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsHexadecimal(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"abcdefg", false}, {"", false}, {"..", false}, {"deadBEEF", true}, {"ff0044", true}, } for _, test := range tests { actual := IsHexadecimal(test.param) if actual != test.expected { t.Errorf("Expected IsHexadecimal(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsHexcolor(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"", false}, {"#ff", false}, {"fff0", false}, {"#ff12FG", false}, {"CCccCC", true}, {"fff", true}, {"#f00", true}, } for _, test := range tests { actual := IsHexcolor(test.param) if actual != test.expected { t.Errorf("Expected IsHexcolor(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsRGBcolor(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"", false}, {"rgb(0,31,255)", true}, {"rgb(1,349,275)", false}, {"rgb(01,31,255)", false}, {"rgb(0.6,31,255)", false}, {"rgba(0,31,255)", false}, {"rgb(0, 31, 255)", true}, } for _, test := range tests { actual := IsRGBcolor(test.param) if actual != test.expected { t.Errorf("Expected IsRGBcolor(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsNull(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"abacaba", false}, {"", true}, } for _, test := range tests { actual := IsNull(test.param) if actual != test.expected { t.Errorf("Expected IsNull(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsNotNull(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"abacaba", true}, {"", false}, } for _, test := range tests { actual := IsNotNull(test.param) if actual != test.expected { t.Errorf("Expected IsNull(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsIMEI(t *testing.T) { tests := []struct { param string expected bool }{ {"990000862471854", true}, {"351756051523999", true}, {"9900008624718541", false}, {"1", false}, } for _, test := range tests { actual := IsIMEI(test.param) if actual != test.expected { t.Errorf("Expected IsIMEI(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestHasWhitespaceOnly(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"abacaba", false}, {"", false}, {" ", true}, {" \r\n ", true}, {"\014\012\011\013\015", true}, {"\014\012\011\013 abc \015", false}, {"\f\n\t\v\r\f", true}, {"x\n\t\t\t\t", false}, {"\f\n\t \n\n\n \v\r\f", true}, } for _, test := range tests { actual := HasWhitespaceOnly(test.param) if actual != test.expected { t.Errorf("Expected HasWhitespaceOnly(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestHasWhitespace(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"abacaba", false}, {"", false}, {" ", true}, {" \r\n ", true}, {"\014\012\011\013\015", true}, {"\014\012\011\013 abc \015", true}, {"\f\n\t\v\r\f", true}, {"x\n\t\t\t\t", true}, {"\f\n\t \n\n\n \v\r\f", true}, } for _, test := range tests { actual := HasWhitespace(test.param) if actual != test.expected { t.Errorf("Expected HasWhitespace(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsDivisibleBy(t *testing.T) { t.Parallel() var tests = []struct { param1 string param2 string expected bool }{ {"4", "2", true}, {"100", "10", true}, {"", "1", true}, {"123", "foo", false}, {"123", "0", false}, } for _, test := range tests { actual := IsDivisibleBy(test.param1, test.param2) if actual != test.expected { t.Errorf("Expected IsDivisibleBy(%q, %q) to be %v, got %v", test.param1, test.param2, test.expected, actual) } } } // This small example illustrate how to work with IsDivisibleBy function. func ExampleIsDivisibleBy() { println("1024 is divisible by 64: ", IsDivisibleBy("1024", "64")) } func TestIsByteLength(t *testing.T) { t.Parallel() var tests = []struct { param1 string param2 int param3 int expected bool }{ {"abacaba", 100, -1, false}, {"abacaba", 1, 3, false}, {"abacaba", 1, 7, true}, {"abacaba", 0, 8, true}, {"\ufff0", 1, 1, false}, } for _, test := range tests { actual := IsByteLength(test.param1, test.param2, test.param3) if actual != test.expected { t.Errorf("Expected IsByteLength(%q, %q, %q) to be %v, got %v", test.param1, test.param2, test.param3, test.expected, actual) } } } func TestIsJSON(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"", false}, {"145", true}, {"asdf", false}, {"123:f00", false}, {"{\"Name\":\"Alice\",\"Body\":\"Hello\",\"Time\":1294706395881547000}", true}, {"{}", true}, {"{\"Key\":{\"Key\":{\"Key\":123}}}", true}, {"[]", true}, {"null", true}, } for _, test := range tests { actual := IsJSON(test.param) if actual != test.expected { t.Errorf("Expected IsJSON(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsMultibyte(t *testing.T) { t.Parallel() var 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}, {"", true}, } for _, test := range tests { actual := IsMultibyte(test.param) if actual != test.expected { t.Errorf("Expected IsMultibyte(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsASCII(t *testing.T) { t.Parallel() var 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 _, test := range tests { actual := IsASCII(test.param) if actual != test.expected { t.Errorf("Expected IsASCII(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsPrintableASCII(t *testing.T) { t.Parallel() var 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 _, test := range tests { actual := IsPrintableASCII(test.param) if actual != test.expected { t.Errorf("Expected IsPrintableASCII(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsFullWidth(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"", true}, {"abc", false}, {"abc123", false}, {"!\"#$%&()<>/+=-_? ~^|.,@`{}[]", false}, {"ひらがな・カタカナ、.漢字", true}, {"3ー0 a@com", true}, {"Fカタカナ゙ᆲ", true}, {"Good=Parts", true}, {"", true}, } for _, test := range tests { actual := IsFullWidth(test.param) if actual != test.expected { t.Errorf("Expected IsFullWidth(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsHalfWidth(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"", true}, {"あいうえお", false}, {"0011", false}, {"!\"#$%&()<>/+=-_? ~^|.,@`{}[]", true}, {"l-btn_02--active", true}, {"abc123い", true}, {"カタカナ゙ᆲ←", true}, {"", true}, } for _, test := range tests { actual := IsHalfWidth(test.param) if actual != test.expected { t.Errorf("Expected IsHalfWidth(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsVariableWidth(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"", true}, {"ひらがなカタカナ漢字ABCDE", true}, {"3ー0123", true}, {"Fカタカナ゙ᆲ", true}, {"", true}, {"Good=Parts", true}, {"abc", false}, {"abc123", false}, {"!\"#$%&()<>/+=-_? ~^|.,@`{}[]", false}, {"ひらがな・カタカナ、.漢字", false}, {"123456", false}, {"カタカナ゙ᆲ", false}, } for _, test := range tests { actual := IsVariableWidth(test.param) if actual != test.expected { t.Errorf("Expected IsVariableWidth(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsUUID(t *testing.T) { t.Parallel() // Tests without version var tests = []struct { param string expected bool }{ {"", false}, {"xxxa987fbc9-4bed-3078-cf07-9141ba07c9f3", false}, {"a987fbc9-4bed-3078-cf07-9141ba07c9f3xxx", false}, {"a987fbc94bed3078cf079141ba07c9f3", false}, {"934859", false}, {"987fbc9-4bed-3078-cf07a-9141ba07c9f3", false}, {"aaaaaaaa-1111-1111-aaag-111111111111", false}, {"a987fbc9-4bed-3078-cf07-9141ba07c9f3", true}, } for _, test := range tests { actual := IsUUID(test.param) if actual != test.expected { t.Errorf("Expected IsUUID(%q) to be %v, got %v", test.param, test.expected, actual) } } // UUID ver. 3 tests = []struct { param string expected bool }{ {"", false}, {"412452646", false}, {"xxxa987fbc9-4bed-3078-cf07-9141ba07c9f3", false}, {"a987fbc9-4bed-4078-8f07-9141ba07c9f3", false}, {"a987fbc9-4bed-3078-cf07-9141ba07c9f3", true}, } for _, test := range tests { actual := IsUUIDv3(test.param) if actual != test.expected { t.Errorf("Expected IsUUIDv3(%q) to be %v, got %v", test.param, test.expected, actual) } } // UUID ver. 4 tests = []struct { param string expected bool }{ {"", false}, {"xxxa987fbc9-4bed-3078-cf07-9141ba07c9f3", false}, {"a987fbc9-4bed-5078-af07-9141ba07c9f3", false}, {"934859", false}, {"57b73598-8764-4ad0-a76a-679bb6640eb1", true}, {"625e63f3-58f5-40b7-83a1-a72ad31acffb", true}, } for _, test := range tests { actual := IsUUIDv4(test.param) if actual != test.expected { t.Errorf("Expected IsUUIDv4(%q) to be %v, got %v", test.param, test.expected, actual) } } // UUID ver. 5 tests = []struct { param string expected bool }{ {"", false}, {"xxxa987fbc9-4bed-3078-cf07-9141ba07c9f3", false}, {"9c858901-8a57-4791-81fe-4c455b099bc9", false}, {"a987fbc9-4bed-3078-cf07-9141ba07c9f3", false}, {"987fbc97-4bed-5078-af07-9141ba07c9f3", true}, {"987fbc97-4bed-5078-9f07-9141ba07c9f3", true}, } for _, test := range tests { actual := IsUUIDv5(test.param) if actual != test.expected { t.Errorf("Expected IsUUIDv5(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsULID(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"", false}, {"xxxa987fbc9-4bed-3078-cf07-9141ba07c9f3", false}, {"a987fbc9-4bed-3078-cf07-9141ba07c9f3xxx", false}, {"a987fbc94bed3078cf079141ba07c9f3", false}, {"934859", false}, {"987fbc9-4bed-3078-cf07a-9141ba07c9f3", false}, {"aaaaaaaa-1111-1111-aaag-111111111111", false}, {"0000000000zzzzzzzzzzzzzzzz", true}, {"0123456789zzzzzzzzzzzzzzzz", true}, {"0123456789abcdefghjkmnpqrs", true}, {"7zzzzzzzzzaaaaaaaaaaaaaaaa", true}, {"7zanmkqfpyaaaaaaaaaaaaaaaa", true}, {"7zanmkqfpyaaaaaaaaaaAAAAAA", true}, {"8000000000zzzzzzzzzzzzzzzz", false}, {"8000000001zzzzzzzzzzzzzzzz", false}, {"8123456789zzzzzzzzzzzzzzzz", false}, {"8123456789zzzzzzzzzzzzzzzL", false}, {"8123456789zzzzzzzzzzzzzzzO", false}, {"8123456789zzzzzzzzzzzzzzzu", false}, {"8123456789zzzzzzzzzzzzzzzI", false}, } for _, test := range tests { tc := test t.Run(fmt.Sprintf("%26.26s", tc.param), func(t *testing.T) { actual := IsULID(tc.param) if actual != tc.expected { t.Errorf("Expected IsULID(%q) to be %v, got %v", tc.param, tc.expected, actual) } }) } } func TestIsCreditCard(t *testing.T) { t.Parallel() tests := []struct { name string number string want bool }{ {"empty", "", false}, {"not numbers", "credit card", false}, {"invalid luhn algorithm", "4220855426213389", false}, {"visa", "4220855426222389", true}, {"visa spaces", "4220 8554 2622 2389", true}, {"visa dashes", "4220-8554-2622-2389", true}, {"mastercard", "5139288802098206", true}, {"american express", "374953669708156", true}, {"discover", "6011464355444102", true}, {"jcb", "3548209662790989", true}, // below should be valid, do they respect international standards? // is our validator logic not correct? {"diners club international", "30190239451016", false}, {"rupay", "6521674451993089", false}, {"mir", "2204151414444676", false}, {"china unionPay", "624356436327468104", false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := IsCreditCard(tt.number); got != tt.want { t.Errorf("IsCreditCard(%v) = %v, want %v", tt.number, got, tt.want) } }) } } func TestIsISBN(t *testing.T) { t.Parallel() // Without version var tests = []struct { param string expected bool }{ {"", false}, {"foo", false}, {"3836221195", true}, {"1-61729-085-8", true}, {"3 423 21412 0", true}, {"3 401 01319 X", true}, {"9784873113685", true}, {"978-4-87311-368-5", true}, {"978 3401013190", true}, {"978-3-8362-2119-1", true}, } for _, test := range tests { actual := IsISBN(test.param, -1) if actual != test.expected { t.Errorf("Expected IsISBN(%q, -1) to be %v, got %v", test.param, test.expected, actual) } } // ISBN 10 tests = []struct { param string expected bool }{ {"", false}, {"foo", false}, {"3423214121", false}, {"978-3836221191", false}, {"3-423-21412-1", false}, {"3 423 21412 1", false}, {"3836221195", true}, {"1-61729-085-8", true}, {"3 423 21412 0", true}, {"3 401 01319 X", true}, } for _, test := range tests { actual := IsISBN10(test.param) if actual != test.expected { t.Errorf("Expected IsISBN10(%q) to be %v, got %v", test.param, test.expected, actual) } } // ISBN 13 tests = []struct { param string expected bool }{ {"", false}, {"foo", false}, {"3-8362-2119-5", false}, {"01234567890ab", false}, {"978 3 8362 2119 0", false}, {"9784873113685", true}, {"978-4-87311-368-5", true}, {"978 3401013190", true}, {"978-3-8362-2119-1", true}, } for _, test := range tests { actual := IsISBN13(test.param) if actual != test.expected { t.Errorf("Expected IsISBN13(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsDataURI(t *testing.T) { t.Parallel() var 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 _, test := range tests { actual := IsDataURI(test.param) if actual != test.expected { t.Errorf("Expected IsDataURI(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsMagnetURI(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"magnet:?xt=urn:btih:06E2A9683BF4DA92C73A661AC56F0ECC9C63C5B4&dn=helloword2000&tr=udp://helloworld:1337/announce", true}, {"magnet:?xt=urn:btih:3E30322D5BFC7444B7B1D8DD42404B75D0531DFB&dn=world&tr=udp://world.com:1337", true}, {"magnet:?xt=urn:btih:4ODKSDJBVMSDSNJVBCBFYFBKNRU875DW8D97DWC6&dn=helloworld&tr=udp://helloworld.com:1337", true}, {"magnet:?xt=urn:btih:1GSHJVBDVDVJFYEHKFHEFIO8573898434JBFEGHD&dn=foo&tr=udp://foo.com:1337", true}, {"magnet:?xt=urn:btih:MCJDCYUFHEUD6E2752T7UJNEKHSUGEJFGTFHVBJS&dn=bar&tr=udp://bar.com:1337", true}, {"magnet:?xt=urn:btih:LAKDHWDHEBFRFVUFJENBYYTEUY837562JH2GEFYH&dn=foobar&tr=udp://foobar.com:1337", true}, {"magnet:?xt=urn:btih:MKCJBHCBJDCU725TGEB3Y6RE8EJ2U267UNJFGUID&dn=test&tr=udp://test.com:1337", true}, {"magnet:?xt=urn:btih:UHWY2892JNEJ2GTEYOMDNU67E8ICGICYE92JDUGH&dn=baz&tr=udp://baz.com:1337", true}, {"magnet:?xt=urn:btih:HS263FG8U3GFIDHWD7829BYFCIXB78XIHG7CWCUG&dn=foz&tr=udp://foz.com:1337", true}, {"", false}, {":?xt=urn:btih:06E2A9683BF4DA92C73A661AC56F0ECC9C63C5B4&dn=helloword2000&tr=udp://helloworld:1337/announce", false}, {"magnett:?xt=urn:btih:3E30322D5BFC7444B7B1D8DD42404B75D0531DFB&dn=world&tr=udp://world.com:1337", false}, {"xt=urn:btih:4ODKSDJBVMSDSNJVBCBFYFBKNRU875DW8D97DWC6&dn=helloworld&tr=udp://helloworld.com:1337", false}, {"magneta:?xt=urn:btih:1GSHJVBDVDVJFYEHKFHEFIO8573898434JBFEGHD&dn=foo&tr=udp://foo.com:1337", false}, {"magnet:?xt=uarn:btih:MCJDCYUFHEUD6E2752T7UJNEKHSUGEJFGTFHVBJS&dn=bar&tr=udp://bar.com:1337", false}, {"magnet:?xt=urn:btihz&dn=foobar&tr=udp://foobar.com:1337", false}, {"magnet:?xat=urn:btih:MKCJBHCBJDCU725TGEB3Y6RE8EJ2U267UNJFGUID&dn=test&tr=udp://test.com:1337", false}, {"magnet::?xt=urn:btih:UHWY2892JNEJ2GTEYOMDNU67E8ICGICYE92JDUGH&dn=baz&tr=udp://baz.com:1337", false}, {"magnet:?xt:btih:HS263FG8U3GFIDHWD7829BYFCIXB78XIHG7CWCUG&dn=foz&tr=udp://foz.com:1337", false}, } for _, test := range tests { actual := IsMagnetURI(test.param) if actual != test.expected { t.Errorf("Expected IsMagnetURI(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsBase64(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4=", true}, {"Vml2YW11cyBmZXJtZW50dW0gc2VtcGVyIHBvcnRhLg==", true}, {"U3VzcGVuZGlzc2UgbGVjdHVzIGxlbw==", true}, {"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuMPNS1Ufof9EW/M98FNw" + "UAKrwflsqVxaxQjBQnHQmiI7Vac40t8x7pIb8gLGV6wL7sBTJiPovJ0V7y7oc0Ye" + "rhKh0Rm4skP2z/jHwwZICgGzBvA0rH8xlhUiTvcwDCJ0kc+fh35hNt8srZQM4619" + "FTgB66Xmp4EtVyhpQV+t02g6NzK72oZI0vnAvqhpkxLeLiMCyrI416wHm5Tkukhx" + "QmcL2a6hNOyu0ixX/x2kSFXApEnVrJ+/IxGyfyw8kf4N2IZpW5nEP847lpfj0SZZ" + "Fwrd1mnfnDbYohX2zRptLy2ZUn06Qo9pkG5ntvFEPo9bfZeULtjYzIl6K8gJ2uGZ" + "HQIDAQAB", true}, {"12345", false}, {"", false}, {"Vml2YW11cyBmZXJtZtesting123", false}, } for _, test := range tests { actual := IsBase64(test.param) if actual != test.expected { t.Errorf("Expected IsBase64(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsISO3166Alpha2(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"", false}, {"ABCD", false}, {"A", false}, {"AC", false}, {"AP", false}, {"GER", false}, {"NU", true}, {"DE", true}, {"JP", true}, {"JPN", false}, {"ZWE", false}, {"GER", false}, {"DEU", false}, } for _, test := range tests { actual := IsISO3166Alpha2(test.param) if actual != test.expected { t.Errorf("Expected IsISO3166Alpha2(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsISO3166Alpha3(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"", false}, {"ABCD", false}, {"A", false}, {"AC", false}, {"AP", false}, {"NU", false}, {"DE", false}, {"JP", false}, {"ZWE", true}, {"JPN", true}, {"GER", false}, {"DEU", true}, } for _, test := range tests { actual := IsISO3166Alpha3(test.param) if actual != test.expected { t.Errorf("Expected IsISO3166Alpha3(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsISO693Alpha2(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"", false}, {"abcd", false}, {"a", false}, {"ac", false}, {"ap", false}, {"de", true}, {"DE", false}, {"mk", true}, {"mac", false}, {"sw", true}, {"SW", false}, {"ger", false}, {"deu", false}, } for _, test := range tests { actual := IsISO693Alpha2(test.param) if actual != test.expected { t.Errorf("Expected IsISO693Alpha2(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsISO693Alpha3b(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"", false}, {"abcd", false}, {"a", false}, {"ac", false}, {"ap", false}, {"de", false}, {"DE", false}, {"mkd", false}, {"mac", true}, {"sw", false}, {"SW", false}, {"ger", true}, {"deu", false}, } for _, test := range tests { actual := IsISO693Alpha3b(test.param) if actual != test.expected { t.Errorf("Expected IsISO693Alpha3b(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsIP(t *testing.T) { t.Parallel() // Without version var tests = []struct { param string expected bool }{ {"", false}, {"127.0.0.1", true}, {"0.0.0.0", true}, {"255.255.255.255", true}, {"1.2.3.4", true}, {"::1", true}, {"2001:db8:0000:1:1:1:1:1", true}, {"300.0.0.0", false}, } for _, test := range tests { actual := IsIP(test.param) if actual != test.expected { t.Errorf("Expected IsIP(%q) to be %v, got %v", test.param, test.expected, actual) } } // IPv4 tests = []struct { param string expected bool }{ {"", false}, {"127.0.0.1", true}, {"0.0.0.0", true}, {"255.255.255.255", true}, {"1.2.3.4", true}, {"::1", false}, {"2001:db8:0000:1:1:1:1:1", false}, {"300.0.0.0", false}, } for _, test := range tests { actual := IsIPv4(test.param) if actual != test.expected { t.Errorf("Expected IsIPv4(%q) to be %v, got %v", test.param, test.expected, actual) } } // IPv6 tests = []struct { param string expected bool }{ {"", false}, {"127.0.0.1", false}, {"0.0.0.0", false}, {"255.255.255.255", false}, {"1.2.3.4", false}, {"::1", true}, {"2001:db8:0000:1:1:1:1:1", true}, {"300.0.0.0", false}, } for _, test := range tests { actual := IsIPv6(test.param) if actual != test.expected { t.Errorf("Expected IsIPv6(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsPort(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"1", true}, {"65535", true}, {"0", false}, {"65536", false}, {"65538", false}, } for _, test := range tests { actual := IsPort(test.param) if actual != test.expected { t.Errorf("Expected IsPort(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsDNSName(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"localhost", true}, {"a.bc", true}, {"a.b.", true}, {"a.b..", false}, {"localhost.local", true}, {"localhost.localdomain.intern", true}, {"l.local.intern", true}, {"ru.link.n.svpncloud.com", true}, {"-localhost", false}, {"localhost.-localdomain", false}, {"localhost.localdomain.-int", false}, {"_localhost", true}, {"localhost._localdomain", true}, {"localhost.localdomain._int", true}, {"lÖcalhost", false}, {"localhost.lÖcaldomain", false}, {"localhost.localdomain.üntern", false}, {"__", true}, {"localhost/", false}, {"127.0.0.1", false}, {"[::1]", false}, {"50.50.50.50", false}, {"localhost.localdomain.intern:65535", false}, {"漢字汉字", false}, {"www.jubfvq1v3p38i51622y0dvmdk1mymowjyeu26gbtw9andgynj1gg8z3msb1kl5z6906k846pj3sulm4kiyk82ln5teqj9nsht59opr0cs5ssltx78lfyvml19lfq1wp4usbl0o36cmiykch1vywbttcus1p9yu0669h8fj4ll7a6bmop505908s1m83q2ec2qr9nbvql2589adma3xsq2o38os2z3dmfh2tth4is4ixyfasasasefqwe4t2ub2fz1rme.de", false}, } for _, test := range tests { actual := IsDNSName(test.param) if actual != test.expected { t.Errorf("Expected IsDNS(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsHost(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"localhost", true}, {"localhost.localdomain", true}, {"2001:db8:0000:1:1:1:1:1", true}, {"::1", true}, {"play.golang.org", true}, {"localhost.localdomain.intern:65535", false}, {"-[::1]", false}, {"-localhost", false}, {".localhost", false}, } for _, test := range tests { actual := IsHost(test.param) if actual != test.expected { t.Errorf("Expected IsHost(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsDialString(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"localhost.local:1", true}, {"localhost.localdomain:9090", true}, {"localhost.localdomain.intern:65535", true}, {"127.0.0.1:30000", true}, {"[::1]:80", true}, {"[1200::AB00:1234::2552:7777:1313]:22", false}, {"-localhost:1", false}, {"localhost.-localdomain:9090", false}, {"localhost.localdomain.-int:65535", false}, {"localhost.loc:100000", false}, {"漢字汉字:2", false}, {"www.jubfvq1v3p38i51622y0dvmdk1mymowjyeu26gbtw9andgynj1gg8z3msb1kl5z6906k846pj3sulm4kiyk82ln5teqj9nsht59opr0cs5ssltx78lfyvml19lfq1wp4usbl0o36cmiykch1vywbttcus1p9yu0669h8fj4ll7a6bmop505908s1m83q2ec2qr9nbvql2589adma3xsq2o38os2z3dmfh2tth4is4ixyfasasasefqwe4t2ub2fz1rme.de:20000", false}, } for _, test := range tests { actual := IsDialString(test.param) if actual != test.expected { t.Errorf("Expected IsDialString(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsMAC(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"3D:F2:C9:A6:B3:4F", true}, {"3D-F2-C9-A6-B3:4F", false}, {"123", false}, {"", false}, {"abacaba", false}, } for _, test := range tests { actual := IsMAC(test.param) if actual != test.expected { t.Errorf("Expected IsMAC(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestFilePath(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool osType int }{ {"c:\\" + strings.Repeat("a", 32767), true, Win}, //See http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx#maxpath {"c:\\" + strings.Repeat("a", 32768), false, Win}, {"c:\\path\\file (x86)\bar", true, Win}, {"c:\\path\\file", true, Win}, {"c:\\path\\file:exe", false, Unknown}, {"C:\\", true, Win}, {"c:\\path\\file\\", true, Win}, {"c:/path/file/", false, Unknown}, {"/path/file/", true, Unix}, {"/path/file:SAMPLE/", true, Unix}, {"/path/file:/.txt", true, Unix}, {"/path", true, Unix}, {"/path/__bc/file.txt", true, Unix}, {"/path/a--ac/file.txt", true, Unix}, {"/_path/file.txt", true, Unix}, {"/path/__bc/file.txt", true, Unix}, {"/path/a--ac/file.txt", true, Unix}, {"/__path/--file.txt", true, Unix}, {"/path/a bc", true, Unix}, } for _, test := range tests { actual, osType := IsFilePath(test.param) if actual != test.expected || osType != test.osType { t.Errorf("Expected IsFilePath(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsWinFilePath(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"c:\\" + strings.Repeat("a", 32767), true}, //See http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx#maxpath {"c:\\" + strings.Repeat("a", 32768), false}, {"c:\\path\\file (x86)\\bar", true}, {"c:\\path\\file", true}, {"c:\\path\\file:exe", false}, {"C:\\", true}, {"c:\\path\\file\\", true}, {"..\\path\\file\\", true}, {"c:/path/file/", false}, {"a bc", true}, {"abc.jd", true}, {"abc.jd:$#%# dsd", false}, } for _, test := range tests { actual := IsWinFilePath(test.param) if actual != test.expected { t.Errorf("Expected IsWinFilePath(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsUnixFilePath(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"c:/path/file/", true}, //relative path {"../path/file/", true}, //relative path {"../../path/file/", true}, //relative path {"./path/file/", true}, //relative path {"./file.dghdg", true}, //relative path {"/path/file/", true}, {"/path/file:SAMPLE/", true}, {"/path/file:/.txt", true}, {"/path", true}, {"/path/__bc/file.txt", true}, {"/path/a--ac/file.txt", true}, {"/_path/file.txt", true}, {"/path/__bc/file.txt", true}, {"/path/a--ac/file.txt", true}, {"/__path/--file.txt", true}, {"/path/a bc", true}, {"a bc", true}, {"abc.jd", true}, {"abc.jd:$#%# dsd", true}, } for _, test := range tests { actual := IsUnixFilePath(test.param) if actual != test.expected { t.Errorf("Expected IsUnixFilePath(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsLatitude(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"", false}, {"-90.000", true}, {"+90", true}, {"47.1231231", true}, {"+99.9", false}, {"108", false}, } for _, test := range tests { actual := IsLatitude(test.param) if actual != test.expected { t.Errorf("Expected IsLatitude(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsLongitude(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"", false}, {"-180.000", true}, {"180.1", false}, {"+73.234", true}, {"+382.3811", false}, {"23.11111111", true}, } for _, test := range tests { actual := IsLongitude(test.param) if actual != test.expected { t.Errorf("Expected IsLongitude(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsSSN(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"", false}, {"00-90-8787", false}, {"66690-76", false}, {"191 60 2869", true}, {"191-60-2869", true}, } for _, test := range tests { actual := IsSSN(test.param) if actual != test.expected { t.Errorf("Expected IsSSN(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsMongoID(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"507f1f77bcf86cd799439011", true}, {"507f1f77bcf86cd7994390", false}, {"507f1f77bcf86cd79943901z", false}, {"507f1f77bcf86cd799439011 ", false}, {"", false}, } for _, test := range tests { actual := IsMongoID(test.param) if actual != test.expected { t.Errorf("Expected IsMongoID(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsSemver(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"v1.0.0", true}, {"1.0.0", true}, {"1.1.01", false}, {"1.01.0", false}, {"01.1.0", false}, {"v1.1.01", false}, {"v1.01.0", false}, {"v01.1.0", false}, {"1.0.0-alpha", true}, {"1.0.0-alpha.1", true}, {"1.0.0-0.3.7", true}, {"1.0.0-0.03.7", false}, {"1.0.0-00.3.7", false}, {"1.0.0-x.7.z.92", true}, {"1.0.0-alpha+001", true}, {"1.0.0+20130313144700", true}, {"1.0.0-beta+exp.sha.5114f85", true}, {"1.0.0-beta+exp.sha.05114f85", true}, {"1.0.0-+beta", false}, {"1.0.0-b+-9+eta", false}, {"v+1.8.0-b+-9+eta", false}, } for _, test := range tests { actual := IsSemver(test.param) if actual != test.expected { t.Errorf("Expected IsSemver(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsTime(t *testing.T) { t.Parallel() var tests = []struct { param string format string expected bool }{ {"2016-12-31 11:00", time.RFC3339, false}, {"2016-12-31 11:00:00", time.RFC3339, false}, {"2016-12-31T11:00", time.RFC3339, false}, {"2016-12-31T11:00:00", time.RFC3339, false}, {"2016-12-31T11:00:00Z", time.RFC3339, true}, {"2016-12-31T11:00:00+01:00", time.RFC3339, true}, {"2016-12-31T11:00:00-01:00", time.RFC3339, true}, {"2016-12-31T11:00:00.05Z", time.RFC3339, true}, {"2016-12-31T11:00:00.05-01:00", time.RFC3339, true}, {"2016-12-31T11:00:00.05+01:00", time.RFC3339, true}, {"2016-12-31T11:00:00", rfc3339WithoutZone, true}, {"2016-12-31T11:00:00Z", rfc3339WithoutZone, false}, {"2016-12-31T11:00:00+01:00", rfc3339WithoutZone, false}, {"2016-12-31T11:00:00-01:00", rfc3339WithoutZone, false}, {"2016-12-31T11:00:00.05Z", rfc3339WithoutZone, false}, {"2016-12-31T11:00:00.05-01:00", rfc3339WithoutZone, false}, {"2016-12-31T11:00:00.05+01:00", rfc3339WithoutZone, false}, } for _, test := range tests { actual := IsTime(test.param, test.format) if actual != test.expected { t.Errorf("Expected IsTime(%q, time.RFC3339) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsRFC3339(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"2016-12-31 11:00", false}, {"2016-12-31 11:00:00", false}, {"2016-12-31T11:00", false}, {"2016-12-31T11:00:00", false}, {"2016-12-31T11:00:00Z", true}, {"2016-12-31T11:00:00+01:00", true}, {"2016-12-31T11:00:00-01:00", true}, {"2016-12-31T11:00:00.05Z", true}, {"2016-12-31T11:00:00.05-01:00", true}, {"2016-12-31T11:00:00.05+01:00", true}, } for _, test := range tests { actual := IsRFC3339(test.param) if actual != test.expected { t.Errorf("Expected IsRFC3339(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsISO4217(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"", false}, {"ABCD", false}, {"A", false}, {"ZZZ", false}, {"usd", false}, {"USD", true}, } for _, test := range tests { actual := IsISO4217(test.param) if actual != test.expected { t.Errorf("Expected IsISO4217(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestByteLength(t *testing.T) { t.Parallel() var tests = []struct { value string min string max string expected bool }{ {"123456", "0", "100", true}, {"1239999", "0", "0", false}, {"1239asdfasf99", "100", "200", false}, {"1239999asdff29", "10", "30", true}, {"你", "0", "1", false}, } for _, test := range tests { actual := ByteLength(test.value, test.min, test.max) if actual != test.expected { t.Errorf("Expected ByteLength(%s, %s, %s) to be %v, got %v", test.value, test.min, test.max, test.expected, actual) } } } func TestRuneLength(t *testing.T) { t.Parallel() var tests = []struct { value string min string max string expected bool }{ {"123456", "0", "100", true}, {"1239999", "0", "0", false}, {"1239asdfasf99", "100", "200", false}, {"1239999asdff29", "10", "30", true}, {"你", "0", "1", true}, } for _, test := range tests { actual := RuneLength(test.value, test.min, test.max) if actual != test.expected { t.Errorf("Expected RuneLength(%s, %s, %s) to be %v, got %v", test.value, test.min, test.max, test.expected, actual) } } } func TestStringLength(t *testing.T) { t.Parallel() var tests = []struct { value string min string max string expected bool }{ {"123456", "0", "100", true}, {"1239999", "0", "0", false}, {"1239asdfasf99", "100", "200", false}, {"1239999asdff29", "10", "30", true}, {"あいうえお", "0", "5", true}, {"あいうえおか", "0", "5", false}, {"あいうえお", "0", "0", false}, {"あいうえ", "5", "10", false}, } for _, test := range tests { actual := StringLength(test.value, test.min, test.max) if actual != test.expected { t.Errorf("Expected StringLength(%s, %s, %s) to be %v, got %v", test.value, test.min, test.max, test.expected, actual) } } } func TestIsIn(t *testing.T) { t.Parallel() var tests = []struct { value string params []string expected bool }{ {"PRESENT", []string{"PRESENT"}, true}, {"PRESENT", []string{"PRESENT", "PRÉSENTE", "NOTABSENT"}, true}, {"PRÉSENTE", []string{"PRESENT", "PRÉSENTE", "NOTABSENT"}, true}, {"PRESENT", []string{}, false}, {"PRESENT", nil, false}, {"ABSENT", []string{"PRESENT", "PRÉSENTE", "NOTABSENT"}, false}, {"", []string{"PRESENT", "PRÉSENTE", "NOTABSENT"}, false}, } for _, test := range tests { actual := IsIn(test.value, test.params...) if actual != test.expected { t.Errorf("Expected IsIn(%s, %v) to be %v, got %v", test.value, test.params, test.expected, actual) } } } type Address struct { Street string `valid:"-"` Zip string `json:"zip" valid:"numeric,required"` } type User struct { Name string `valid:"required"` Email string `valid:"required,email"` Password string `valid:"required"` Age int `valid:"required,numeric,@#\u0000"` Home *Address Work []Address } type UserValid struct { Name string `valid:"required"` Email string `valid:"required,email"` Password string `valid:"required"` Age int `valid:"required"` Home *Address Work []Address `valid:"required"` } type PrivateStruct struct { privateField string `valid:"required,alpha,d_k"` NonZero int ListInt []int ListString []string `valid:"alpha"` Work [2]Address Home Address Map map[string]Address } type NegationStruct struct { NotInt string `valid:"!int"` Int string `valid:"int"` } type LengthStruct struct { Length string `valid:"length(10|20)"` } type StringLengthStruct struct { Length string `valid:"stringlength(10|20)"` } type StringMatchesStruct struct { StringMatches string `valid:"matches(^[0-9]{3}$)"` } // TODO: this testcase should be fixed // type StringMatchesComplexStruct struct { // StringMatches string `valid:"matches(^\\$\\([\"']\\w+[\"']\\)$)"` // } type IsInStruct struct { IsIn string `valid:"in(PRESENT|PRÉSENTE|NOTABSENT)"` } type Post struct { Title string `valid:"alpha,required"` Message string `valid:"ascii"` AuthorIP string `valid:"ipv4"` } type MissingValidationDeclarationStruct struct { Name string `` Email string `valid:"required,email"` } type FieldRequiredByDefault struct { Email string `valid:"email"` } type MultipleFieldsRequiredByDefault struct { Url string `valid:"url"` Email string `valid:"email"` } type FieldsRequiredByDefaultButExemptStruct struct { Name string `valid:"-"` Email string `valid:"email"` } type FieldsRequiredByDefaultButExemptOrOptionalStruct struct { Name string `valid:"-"` Email string `valid:"optional,email"` } type MessageWithSeveralFieldsStruct struct { Title string `valid:"length(1|10)"` Body string `valid:"length(1|10)"` } func TestValidateMissingValidationDeclarationStruct(t *testing.T) { var tests = []struct { param MissingValidationDeclarationStruct expected bool }{ {MissingValidationDeclarationStruct{}, false}, {MissingValidationDeclarationStruct{Name: "TEST", Email: "test@example.com"}, false}, } SetFieldsRequiredByDefault(true) for _, test := range tests { actual, err := ValidateStruct(test.param) if actual != test.expected { t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual) if err != nil { t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err) } } } SetFieldsRequiredByDefault(false) } func TestFieldRequiredByDefault(t *testing.T) { var tests = []struct { param FieldRequiredByDefault expected bool }{ {FieldRequiredByDefault{}, false}, } SetFieldsRequiredByDefault(true) for _, test := range tests { actual, err := ValidateStruct(test.param) if actual != test.expected { t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual) if err != nil { t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err) } } } SetFieldsRequiredByDefault(false) } func TestMultipleFieldsRequiredByDefault(t *testing.T) { var tests = []struct { param MultipleFieldsRequiredByDefault expected bool }{ {MultipleFieldsRequiredByDefault{}, false}, } SetFieldsRequiredByDefault(true) for _, test := range tests { actual, err := ValidateStruct(test.param) if actual != test.expected { t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual) if err != nil { t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err) } } } SetFieldsRequiredByDefault(false) } func TestFieldsRequiredByDefaultButExemptStruct(t *testing.T) { var tests = []struct { param FieldsRequiredByDefaultButExemptStruct expected bool }{ {FieldsRequiredByDefaultButExemptStruct{}, false}, {FieldsRequiredByDefaultButExemptStruct{Name: "TEST"}, false}, {FieldsRequiredByDefaultButExemptStruct{Email: ""}, false}, {FieldsRequiredByDefaultButExemptStruct{Email: "test@example.com"}, true}, } SetFieldsRequiredByDefault(true) for _, test := range tests { actual, err := ValidateStruct(test.param) if actual != test.expected { t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual) if err != nil { t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err) } } } SetFieldsRequiredByDefault(false) } func TestFieldsRequiredByDefaultButExemptOrOptionalStruct(t *testing.T) { var tests = []struct { param FieldsRequiredByDefaultButExemptOrOptionalStruct expected bool }{ {FieldsRequiredByDefaultButExemptOrOptionalStruct{}, true}, {FieldsRequiredByDefaultButExemptOrOptionalStruct{Name: "TEST"}, true}, {FieldsRequiredByDefaultButExemptOrOptionalStruct{Email: ""}, true}, {FieldsRequiredByDefaultButExemptOrOptionalStruct{Email: "test@example.com"}, true}, {FieldsRequiredByDefaultButExemptOrOptionalStruct{Email: "test@example"}, false}, } SetFieldsRequiredByDefault(true) for _, test := range tests { actual, err := ValidateStruct(test.param) if actual != test.expected { t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual) if err != nil { t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err) } } } SetFieldsRequiredByDefault(false) } func TestInvalidValidator(t *testing.T) { type InvalidStruct struct { Field int `valid:"someInvalidValidator"` } invalidStruct := InvalidStruct{1} if valid, err := ValidateStruct(&invalidStruct); valid || err == nil || err.Error() != `Field: The following validator is invalid or can't be applied to the field: "someInvalidValidator"` { t.Errorf("Got an unexpected result for struct with invalid validator: %t %s", valid, err) } } func TestCustomValidator(t *testing.T) { type ValidStruct struct { Field int `valid:"customTrueValidator"` } type InvalidStruct struct { Field int `valid:"customFalseValidator~Value: %s Custom validator error: %s"` } type StructWithCustomAndBuiltinValidator struct { Field int `valid:"customTrueValidator,required"` } if valid, err := ValidateStruct(&ValidStruct{Field: 1}); !valid || err != nil { t.Errorf("Got an unexpected result for struct with custom always true validator: %t %s", valid, err) } if valid, err := ValidateStruct(&InvalidStruct{Field: 1}); valid || err == nil || err.Error() != "Value: 1 Custom validator error: customFalseValidator" { fmt.Println(err) t.Errorf("Got an unexpected result for struct with custom always false validator: %t %s", valid, err) } mixedStruct := StructWithCustomAndBuiltinValidator{} if valid, err := ValidateStruct(&mixedStruct); valid || err == nil || err.Error() != "Field: non zero value required" { t.Errorf("Got an unexpected result for invalid struct with custom and built-in validators: %t %s", valid, err) } mixedStruct.Field = 1 if valid, err := ValidateStruct(&mixedStruct); !valid || err != nil { t.Errorf("Got an unexpected result for valid struct with custom and built-in validators: %t %s", valid, err) } } type CustomByteArray [6]byte type StructWithCustomByteArray struct { ID CustomByteArray `valid:"customByteArrayValidator,customMinLengthValidator"` Email string `valid:"email"` CustomMinLength int `valid:"-"` } func TestStructWithCustomByteArray(t *testing.T) { t.Parallel() // add our custom byte array validator that fails when the byte array is pristine (all zeroes) CustomTypeTagMap.Set("customByteArrayValidator", CustomTypeValidator(func(i interface{}, o interface{}) bool { switch v := o.(type) { case StructWithCustomByteArray: if len(v.Email) > 0 { if v.Email != "test@example.com" { t.Errorf("v.Email should have been 'test@example.com' but was '%s'", v.Email) } } default: t.Errorf("Context object passed to custom validator should have been a StructWithCustomByteArray but was %T (%+v)", o, o) } switch v := i.(type) { case CustomByteArray: for _, e := range v { // checks if v is empty, i.e. all zeroes if e != 0 { return true } } } return false })) CustomTypeTagMap.Set("customMinLengthValidator", CustomTypeValidator(func(i interface{}, o interface{}) bool { switch v := o.(type) { case StructWithCustomByteArray: return len(v.ID) >= v.CustomMinLength } return false })) testCustomByteArray := CustomByteArray{'1', '2', '3', '4', '5', '6'} var tests = []struct { param StructWithCustomByteArray expected bool }{ {StructWithCustomByteArray{}, false}, {StructWithCustomByteArray{Email: "test@example.com"}, false}, {StructWithCustomByteArray{ID: testCustomByteArray, Email: "test@example.com"}, true}, {StructWithCustomByteArray{ID: testCustomByteArray, Email: "test@example.com", CustomMinLength: 7}, false}, } SetFieldsRequiredByDefault(true) for _, test := range tests { actual, err := ValidateStruct(test.param) if actual != test.expected { t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual) if err != nil { t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err) } } } SetFieldsRequiredByDefault(false) } func TestValidateNegationStruct(t *testing.T) { var tests = []struct { param NegationStruct expected bool }{ {NegationStruct{"a1", "11"}, true}, {NegationStruct{"email@email.email", "11"}, true}, {NegationStruct{"123456----", "11"}, true}, {NegationStruct{"::1", "11"}, true}, {NegationStruct{"123.123", "11"}, true}, {NegationStruct{"a1", "a1"}, false}, {NegationStruct{"11", "a1"}, false}, {NegationStruct{"11", "11"}, false}, } for _, test := range tests { actual, err := ValidateStruct(test.param) if actual != test.expected { t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual) if err != nil { t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err) } } } } func TestLengthStruct(t *testing.T) { var tests = []struct { param interface{} expected bool }{ {LengthStruct{"11111"}, false}, {LengthStruct{"11111111111111111110000000000000000"}, false}, {LengthStruct{"11dfffdf0099"}, true}, } for _, test := range tests { actual, err := ValidateStruct(test.param) if actual != test.expected { t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual) if err != nil { t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err) } } } } func TestStringLengthStruct(t *testing.T) { var tests = []struct { param interface{} expected bool }{ {StringLengthStruct{"11111"}, false}, {StringLengthStruct{"11111111111111111110000000000000000"}, false}, {StringLengthStruct{"11dfffdf0099"}, true}, {StringLengthStruct{"あいうえお"}, false}, {StringLengthStruct{"あいうえおかきくけこ"}, true}, {StringLengthStruct{"あいうえおかきくけこさしすせそたちつてと"}, true}, {StringLengthStruct{"あいうえおかきくけこさしすせそたちつてとな"}, false}, } for _, test := range tests { actual, err := ValidateStruct(test.param) if actual != test.expected { t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual) if err != nil { t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err) } } } } func TestStringMatchesStruct(t *testing.T) { var tests = []struct { param interface{} expected bool }{ {StringMatchesStruct{"123"}, true}, {StringMatchesStruct{"123456"}, false}, {StringMatchesStruct{"123abcd"}, false}, } for _, test := range tests { actual, err := ValidateStruct(test.param) if actual != test.expected { t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual) if err != nil { t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err) } } } } func TestIsInStruct(t *testing.T) { var tests = []struct { param interface{} expected bool }{ {IsInStruct{"PRESENT"}, true}, {IsInStruct{""}, true}, {IsInStruct{" "}, false}, {IsInStruct{"ABSENT"}, false}, } for _, test := range tests { actual, err := ValidateStruct(test.param) if actual != test.expected { t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual) if err != nil { t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err) } } } } func TestRequiredIsInStruct(t *testing.T) { type RequiredIsInStruct struct { IsIn string `valid:"in(PRESENT|PRÉSENTE|NOTABSENT),required"` } var tests = []struct { param interface{} expected bool }{ {RequiredIsInStruct{"PRESENT"}, true}, {RequiredIsInStruct{""}, false}, {RequiredIsInStruct{" "}, false}, {RequiredIsInStruct{"ABSENT"}, false}, } for _, test := range tests { actual, err := ValidateStruct(test.param) if actual != test.expected { t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual) if err != nil { t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err) } } } } func TestEmptyRequiredIsInStruct(t *testing.T) { type EmptyRequiredIsInStruct struct { IsIn string `valid:"in(),required"` } var tests = []struct { param interface{} expected bool }{ {EmptyRequiredIsInStruct{"PRESENT"}, false}, {EmptyRequiredIsInStruct{""}, false}, {EmptyRequiredIsInStruct{" "}, false}, {EmptyRequiredIsInStruct{"ABSENT"}, false}, } for _, test := range tests { actual, err := ValidateStruct(test.param) if actual != test.expected { t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual) if err != nil { t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err) } } } } func TestEmptyStringPtr(t *testing.T) { type EmptyIsInStruct struct { IsIn *string `valid:"length(3|5),required"` } var empty = "" var valid = "123" var invalid = "123456" var tests = []struct { param interface{} expected bool expectedErr string }{ {EmptyIsInStruct{&empty}, false, "IsIn: non zero value required"}, {EmptyIsInStruct{nil}, true, ""}, {EmptyIsInStruct{&valid}, true, ""}, {EmptyIsInStruct{&invalid}, false, "IsIn: 123456 does not validate as length(3|5)"}, } SetNilPtrAllowedByRequired(true) for _, test := range tests { actual, err := ValidateStruct(test.param) if actual != test.expected { t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual) } if err != nil { if err.Error() != test.expectedErr { t.Errorf("Got Error on ValidateStruct(%q). Expected: %s Actual: %s", test.param, test.expectedErr, err) } } else if test.expectedErr != "" { t.Errorf("Expected error on ValidateStruct(%q).", test.param) } } SetNilPtrAllowedByRequired(false) } func TestNestedStruct(t *testing.T) { type EvenMoreNestedStruct struct { Bar string `valid:"length(3|5)"` } type NestedStruct struct { Foo string `valid:"length(3|5),required"` EvenMoreNested EvenMoreNestedStruct SliceEvenMoreNested []EvenMoreNestedStruct MapEvenMoreNested map[string]EvenMoreNestedStruct } type OuterStruct struct { Nested NestedStruct } var tests = []struct { param interface{} expected bool expectedErr string }{ {OuterStruct{ Nested: NestedStruct{ Foo: "", }, }, false, "Nested.Foo: non zero value required"}, {OuterStruct{ Nested: NestedStruct{ Foo: "123", }, }, true, ""}, {OuterStruct{ Nested: NestedStruct{ Foo: "123456", }, }, false, "Nested.Foo: 123456 does not validate as length(3|5)"}, {OuterStruct{ Nested: NestedStruct{ Foo: "123", EvenMoreNested: EvenMoreNestedStruct{ Bar: "123456", }, }, }, false, "Nested.EvenMoreNested.Bar: 123456 does not validate as length(3|5)"}, {OuterStruct{ Nested: NestedStruct{ Foo: "123", SliceEvenMoreNested: []EvenMoreNestedStruct{ { Bar: "123456", }, }, }, }, false, "Nested.SliceEvenMoreNested.0.Bar: 123456 does not validate as length(3|5)"}, {OuterStruct{ Nested: NestedStruct{ Foo: "123", MapEvenMoreNested: map[string]EvenMoreNestedStruct{ "Foo": { Bar: "123456", }, }, }, }, false, "Nested.MapEvenMoreNested.Foo.Bar: 123456 does not validate as length(3|5)"}, } for _, test := range tests { actual, err := ValidateStruct(test.param) if actual != test.expected { t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual) } if err != nil { if err.Error() != test.expectedErr { t.Errorf("Got Error on ValidateStruct(%q). Expected: %s Actual: %s", test.param, test.expectedErr, err) } } else if test.expectedErr != "" { t.Errorf("Expected error on ValidateStruct(%q).", test.param) } } } func TestFunkyIsInStruct(t *testing.T) { type FunkyIsInStruct struct { IsIn string `valid:"in(PRESENT|| |PRÉSENTE|NOTABSENT)"` } var tests = []struct { param interface{} expected bool }{ {FunkyIsInStruct{"PRESENT"}, true}, {FunkyIsInStruct{""}, true}, {FunkyIsInStruct{" "}, true}, {FunkyIsInStruct{"ABSENT"}, false}, } for _, test := range tests { actual, err := ValidateStruct(test.param) if actual != test.expected { t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual) if err != nil { t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err) } } } } // TODO: test case broken // func TestStringMatchesComplexStruct(t *testing.T) { // var tests = []struct { // param interface{} // expected bool // }{ // {StringMatchesComplexStruct{"$()"}, false}, // {StringMatchesComplexStruct{"$('AZERTY')"}, true}, // {StringMatchesComplexStruct{`$("AZERTY")`}, true}, // {StringMatchesComplexStruct{`$("")`}, false}, // {StringMatchesComplexStruct{"AZERTY"}, false}, // {StringMatchesComplexStruct{"$AZERTY"}, false}, // } // for _, test := range tests { // actual, err := ValidateStruct(test.param) // if actual != test.expected { // t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual) // if err != nil { // t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err) // } // } // } // } func TestValidateStruct(t *testing.T) { var tests = []struct { param interface{} expected bool }{ {User{"John", "john@yahoo.com", "123G#678", 20, &Address{"Street", "ABC456D89"}, []Address{{"Street", "123456"}, {"Street", "123456"}}}, false}, {User{"John", "john!yahoo.com", "12345678", 20, &Address{"Street", "ABC456D89"}, []Address{{"Street", "ABC456D89"}, {"Street", "123456"}}}, false}, {User{"John", "", "12345", 0, &Address{"Street", "123456789"}, []Address{{"Street", "ABC456D89"}, {"Street", "123456"}}}, false}, {UserValid{"John", "john@yahoo.com", "123G#678", 20, &Address{"Street", "123456"}, []Address{{"Street", "123456"}, {"Street", "123456"}}}, true}, {UserValid{"John", "john!yahoo.com", "12345678", 20, &Address{"Street", "ABC456D89"}, []Address{}}, false}, {UserValid{"John", "john@yahoo.com", "12345678", 20, &Address{"Street", "123456xxx"}, []Address{{"Street", "123456"}, {"Street", "123456"}}}, false}, {UserValid{"John", "john!yahoo.com", "12345678", 20, &Address{"Street", "ABC456D89"}, []Address{{"Street", "ABC456D89"}, {"Street", "123456"}}}, false}, {UserValid{"John", "", "12345", 0, &Address{"Street", "123456789"}, []Address{{"Street", "ABC456D89"}, {"Street", "123456"}}}, false}, {nil, true}, {User{"John", "john@yahoo.com", "123G#678", 0, &Address{"Street", "123456"}, []Address{}}, false}, {"im not a struct", false}, } for _, test := range tests { actual, err := ValidateStruct(test.param) if actual != test.expected { t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual) if err != nil { t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err) } } } TagMap["d_k"] = Validator(func(str string) bool { return str == "d_k" }) result, err := ValidateStruct(PrivateStruct{"d_k", 0, []int{1, 2}, []string{"hi", "super"}, [2]Address{{"Street", "123456"}, {"Street", "123456"}}, Address{"Street", "123456"}, map[string]Address{"address": {"Street", "123456"}}}) if !result { t.Log("Case ", 6, ": expected ", true, " when result is ", result) t.Error(err) t.FailNow() } } type testByteArray [8]byte type testByteMap map[byte]byte type testByteSlice []byte type testStringStringMap map[string]string type testStringIntMap map[string]int func TestRequired(t *testing.T) { testString := "foobar" testEmptyString := "" var tests = []struct { param interface{} expected bool }{ { struct { Pointer *string `valid:"required"` }{}, false, }, { struct { Pointer *string `valid:"required"` }{ Pointer: &testEmptyString, }, false, }, { struct { Pointer *string `valid:"required"` }{ Pointer: &testString, }, true, }, { struct { Addr Address `valid:"required"` }{}, false, }, { struct { Addr Address `valid:"required"` }{ Addr: Address{"", "123"}, }, true, }, { struct { Pointer *Address `valid:"required"` }{}, false, }, { struct { Pointer *Address `valid:"required"` }{ Pointer: &Address{"", "123"}, }, true, }, { struct { TestByteArray testByteArray `valid:"required"` }{}, false, }, { struct { TestByteArray testByteArray `valid:"required"` }{ testByteArray{}, }, false, }, { struct { TestByteArray testByteArray `valid:"required"` }{ testByteArray{'1', '2', '3', '4', '5', '6', '7', 'A'}, }, true, }, { struct { TestByteMap testByteMap `valid:"required"` }{}, false, }, { struct { TestByteSlice testByteSlice `valid:"required"` }{}, false, }, { struct { TestStringStringMap testStringStringMap `valid:"required"` }{ testStringStringMap{"test": "test"}, }, true, }, { struct { TestIntMap testStringIntMap `valid:"required"` }{ testStringIntMap{"test": 42}, }, true, }, } for _, test := range tests { actual, err := ValidateStruct(test.param) if actual != test.expected { t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual) if err != nil { t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err) } } } } func TestErrorByField(t *testing.T) { t.Parallel() var tests = []struct { param string expected string }{ {"message", ""}, {"Message", ""}, {"title", ""}, {"Title", "My123 does not validate as alpha"}, {"AuthorIP", "123 does not validate as ipv4"}, } post := &Post{"My123", "duck13126", "123"} _, err := ValidateStruct(post) for _, test := range tests { actual := ErrorByField(err, test.param) if actual != test.expected { t.Errorf("Expected ErrorByField(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestErrorsByField(t *testing.T) { t.Parallel() var tests = []struct { param string expected string }{ {"Title", "My123 does not validate as alpha"}, {"AuthorIP", "123 does not validate as ipv4"}, } post := &Post{Title: "My123", Message: "duck13126", AuthorIP: "123"} _, err := ValidateStruct(post) errs := ErrorsByField(err) if len(errs) != 2 { t.Errorf("There should only be 2 errors but got %v", len(errs)) } for _, test := range tests { if actual, ok := errs[test.param]; !ok || actual != test.expected { t.Errorf("Expected ErrorsByField(%q) to be %v, got %v", test.param, test.expected, actual) } } tests = []struct { param string expected string }{ {"Title", ";:;message;:; does not validate as length(1|10)"}, {"Body", ";:;message;:; does not validate as length(1|10)"}, } message := &MessageWithSeveralFieldsStruct{Title: ";:;message;:;", Body: ";:;message;:;"} _, err = ValidateStruct(message) errs = ErrorsByField(err) if len(errs) != 2 { t.Errorf("There should only be 2 errors but got %v", len(errs)) } for _, test := range tests { if actual, ok := errs[test.param]; !ok || actual != test.expected { t.Errorf("Expected ErrorsByField(%q) to be %v, got %v", test.param, test.expected, actual) } } tests = []struct { param string expected string }{ {"CustomField", "An error occurred"}, } err = Error{"CustomField", fmt.Errorf("An error occurred"), false, "hello", []string{}} errs = ErrorsByField(err) if len(errs) != 1 { t.Errorf("There should only be 1 errors but got %v", len(errs)) } for _, test := range tests { if actual, ok := errs[test.param]; !ok || actual != test.expected { t.Errorf("Expected ErrorsByField(%q) to be %v, got %v", test.param, test.expected, actual) } } type StructWithCustomValidation struct { Email string `valid:"email"` ID string `valid:"falseValidation"` } CustomTypeTagMap.Set("falseValidation", CustomTypeValidator(func(i interface{}, o interface{}) bool { return false })) tests = []struct { param string expected string }{ {"Email", "My123 does not validate as email"}, {"ID", "duck13126 does not validate as falseValidation"}, } s := &StructWithCustomValidation{Email: "My123", ID: "duck13126"} _, err = ValidateStruct(s) errs = ErrorsByField(err) if len(errs) != 2 { t.Errorf("There should only be 2 errors but got %v", len(errs)) } for _, test := range tests { if actual, ok := errs[test.param]; !ok || actual != test.expected { t.Errorf("Expected ErrorsByField(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestValidateStructPointers(t *testing.T) { // Struct which uses pointers for values type UserWithPointers struct { Name *string `valid:"-"` Email *string `valid:"email"` FavoriteFood *string `valid:"length(0|32)"` Nerd *bool `valid:"-"` } var tests = []struct { param string expected string }{ {"Name", ""}, {"Email", "invalid does not validate as email"}, {"FavoriteFood", ""}, {"Nerd", ""}, } name := "Herman" email := "invalid" food := "Pizza" nerd := true user := &UserWithPointers{&name, &email, &food, &nerd} _, err := ValidateStruct(user) for _, test := range tests { actual := ErrorByField(err, test.param) if actual != test.expected { t.Errorf("Expected ErrorByField(%q) to be %v, got %v", test.param, test.expected, actual) } } } func ExampleValidateStruct() { type Post struct { Title string `valid:"alphanum,required"` Message string `valid:"duck,ascii"` AuthorIP string `valid:"ipv4"` } post := &Post{"My Example Post", "duck", "123.234.54.3"} //Add your own struct validation tags TagMap["duck"] = Validator(func(str string) bool { return str == "duck" }) result, err := ValidateStruct(post) if err != nil { println("error: " + err.Error()) } println(result) } func TestValidateStructParamValidatorInt(t *testing.T) { type Test1 struct { Int int `valid:"range(1|10)"` Int8 int8 `valid:"range(1|10)"` Int16 int16 `valid:"range(1|10)"` Int32 int32 `valid:"range(1|10)"` Int64 int64 `valid:"range(1|10)"` Uint uint `valid:"range(1|10)"` Uint8 uint8 `valid:"range(1|10)"` Uint16 uint16 `valid:"range(1|10)"` Uint32 uint32 `valid:"range(1|10)"` Uint64 uint64 `valid:"range(1|10)"` Float32 float32 `valid:"range(1|10)"` Float64 float64 `valid:"range(1|10)"` } test1Ok := &Test1{5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5} test1NotOk := &Test1{11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11} _, err := ValidateStruct(test1Ok) if err != nil { t.Errorf("Test failed: %s", err) } _, err = ValidateStruct(test1NotOk) if err == nil { t.Errorf("Test failed: nil") } type Test2 struct { Int int `valid:"in(1|10)"` Int8 int8 `valid:"in(1|10)"` Int16 int16 `valid:"in(1|10)"` Int32 int32 `valid:"in(1|10)"` Int64 int64 `valid:"in(1|10)"` Uint uint `valid:"in(1|10)"` Uint8 uint8 `valid:"in(1|10)"` Uint16 uint16 `valid:"in(1|10)"` Uint32 uint32 `valid:"in(1|10)"` Uint64 uint64 `valid:"in(1|10)"` Float32 float32 `valid:"in(1|10)"` Float64 float64 `valid:"in(1|10)"` } test2Ok1 := &Test2{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} test2Ok2 := &Test2{10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10} test2NotOk := &Test2{2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2} _, err = ValidateStruct(test2Ok1) if err != nil { t.Errorf("Test failed: %s", err) } _, err = ValidateStruct(test2Ok2) if err != nil { t.Errorf("Test failed: %s", err) } _, err = ValidateStruct(test2NotOk) if err == nil { t.Errorf("Test failed: nil") } type Test3 struct { Int int `valid:"in(1|10),int"` Int8 int8 `valid:"in(1|10),int8"` Int16 int16 `valid:"in(1|10),int16"` Int32 int32 `valid:"in(1|10),int32"` Int64 int64 `valid:"in(1|10),int64"` Uint uint `valid:"in(1|10),uint"` Uint8 uint8 `valid:"in(1|10),uint8"` Uint16 uint16 `valid:"in(1|10),uint16"` Uint32 uint32 `valid:"in(1|10),uint32"` Uint64 uint64 `valid:"in(1|10),uint64"` Float32 float32 `valid:"in(1|10),float32"` Float64 float64 `valid:"in(1|10),float64"` } test3Ok1 := &Test2{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} test3Ok2 := &Test2{10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10} test3NotOk := &Test2{2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2} _, err = ValidateStruct(test3Ok1) if err != nil { t.Errorf("Test failed: %s", err) } _, err = ValidateStruct(test3Ok2) if err != nil { t.Errorf("Test failed: %s", err) } _, err = ValidateStruct(test3NotOk) if err == nil { t.Errorf("Test failed: nil") } } func TestValidateStructUpperAndLowerCaseWithNumTypeCheck(t *testing.T) { type StructCapital struct { Total float32 `valid:"float,required"` } structCapital := &StructCapital{53.3535} _, err := ValidateStruct(structCapital) if err != nil { t.Errorf("Test failed: nil") fmt.Println(err) } type StructLower struct { total float32 `valid:"float,required"` } structLower := &StructLower{53.3535} _, err = ValidateStruct(structLower) if err != nil { t.Errorf("Test failed: nil") fmt.Println(err) } } func TestIsCIDR(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"193.168.3.20/7", true}, {"2001:db8::/32", true}, {"2001:0db8:85a3:0000:0000:8a2e:0370:7334/64", true}, {"193.138.3.20/60", false}, {"500.323.2.23/43", false}, {"", false}, } for _, test := range tests { actual := IsCIDR(test.param) if actual != test.expected { t.Errorf("Expected IsCIDR(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestOptionalCustomValidators(t *testing.T) { CustomTypeTagMap.Set("f2", CustomTypeValidator(func(i interface{}, o interface{}) bool { return false })) var val struct { WithCustomError string `valid:"f2~boom,optional"` WithoutCustomError string `valid:"f2,optional"` OptionalFirst string `valid:"optional,f2"` } ok, err := ValidateStruct(val) if err != nil { t.Errorf("Expected nil err with optional validation, got %v", err) } if !ok { t.Error("Expected validation to return true, got false") } } func TestJSONValidator(t *testing.T) { var val struct { WithJSONName string `json:"with_json_name" valid:"-,required"` WithoutJSONName string `valid:"-,required"` WithJSONOmit string `json:"with_other_json_name,omitempty" valid:"-,required"` WithJSONOption string `json:",omitempty" valid:"-,required"` WithEmptyJSONName string `json:"-" valid:"-,required"` } _, err := ValidateStruct(val) if err == nil { t.Error("Expected error but got no error") } if Contains(err.Error(), "WithJSONName") { t.Errorf("Expected error message to contain with_json_name but actual error is: %s", err.Error()) } if !Contains(err.Error(), "WithoutJSONName") { t.Errorf("Expected error message to contain WithoutJSONName but actual error is: %s", err.Error()) } if Contains(err.Error(), "omitempty") { t.Errorf("Expected error message to not contain ',omitempty' but actual error is: %s", err.Error()) } if !Contains(err.Error(), "WithEmptyJSONName") { t.Errorf("Expected error message to contain WithEmptyJSONName but actual error is: %s", err.Error()) } } func TestValidatorIncludedInError(t *testing.T) { post := Post{ Title: "", Message: "👍", AuthorIP: "xyz", } validatorMap := map[string]string{ "Title": "required", "Message": "ascii", "AuthorIP": "ipv4", } ok, errors := ValidateStruct(post) if ok { t.Errorf("expected validation to fail %v", ok) } for _, e := range errors.(Errors) { casted := e.(Error) if validatorMap[casted.Name] != casted.Validator { t.Errorf("expected validator for %s to be %s, but was %s", casted.Name, validatorMap[casted.Name], casted.Validator) } } // checks to make sure that validators with arguments (like length(1|10)) don't include the arguments // in the validator name message := MessageWithSeveralFieldsStruct{ Title: "", Body: "asdfasdfasdfasdfasdf", } validatorMap = map[string]string{ "Title": "length", "Body": "length", } ok, errors = ValidateStruct(message) if ok { t.Errorf("expected validation to fail, %v", ok) } for _, e := range errors.(Errors) { casted := e.(Error) if validatorMap[casted.Name] != casted.Validator { t.Errorf("expected validator for %s to be %s, but was %s", casted.Name, validatorMap[casted.Name], casted.Validator) } } // make sure validators with custom messages don't show up in the validator string type CustomMessage struct { Text string `valid:"length(1|10)~Custom message"` } cs := CustomMessage{Text: "asdfasdfasdfasdf"} ok, errors = ValidateStruct(&cs) if ok { t.Errorf("expected validation to fail, %v", ok) } validator := errors.(Errors)[0].(Error).Validator if validator != "length" { t.Errorf("expected validator for Text to be length, but was %s", validator) } } func TestIsRsaPublicKey(t *testing.T) { var tests = []struct { rsastr string keylen int expected bool }{ {`fubar`, 2048, false}, {`MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvncDCeibmEkabJLmFec7x9y86RP6dIvkVxxbQoOJo06E+p7tH6vCmiGHKnuu XwKYLq0DKUE3t/HHsNdowfD9+NH8caLzmXqGBx45/Dzxnwqz0qYq7idK+Qff34qrk/YFoU7498U1Ee7PkKb7/VE9BmMEcI3uoKbeXCbJRI HoTp8bUXOpNTSUfwUNwJzbm2nsHo2xu6virKtAZLTsJFzTUmRd11MrWCvj59lWzt1/eIMN+ekjH8aXeLOOl54CL+kWp48C+V9BchyKCShZ B7ucimFvjHTtuxziXZQRO7HlcsBOa0WwvDJnRnskdyoD31s4F4jpKEYBJNWTo63v6lUvbQIDAQAB`, 2048, true}, {`MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvncDCeibmEkabJLmFec7x9y86RP6dIvkVxxbQoOJo06E+p7tH6vCmiGHKnuu XwKYLq0DKUE3t/HHsNdowfD9+NH8caLzmXqGBx45/Dzxnwqz0qYq7idK+Qff34qrk/YFoU7498U1Ee7PkKb7/VE9BmMEcI3uoKbeXCbJRI HoTp8bUXOpNTSUfwUNwJzbm2nsHo2xu6virKtAZLTsJFzTUmRd11MrWCvj59lWzt1/eIMN+ekjH8aXeLOOl54CL+kWp48C+V9BchyKCShZ B7ucimFvjHTtuxziXZQRO7HlcsBOa0WwvDJnRnskdyoD31s4F4jpKEYBJNWTo63v6lUvbQIDAQAB`, 1024, false}, {`-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvncDCeibmEkabJLmFec7 x9y86RP6dIvkVxxbQoOJo06E+p7tH6vCmiGHKnuuXwKYLq0DKUE3t/HHsNdowfD9 +NH8caLzmXqGBx45/Dzxnwqz0qYq7idK+Qff34qrk/YFoU7498U1Ee7PkKb7/VE9 BmMEcI3uoKbeXCbJRIHoTp8bUXOpNTSUfwUNwJzbm2nsHo2xu6virKtAZLTsJFzT UmRd11MrWCvj59lWzt1/eIMN+ekjH8aXeLOOl54CL+kWp48C+V9BchyKCShZB7uc imFvjHTtuxziXZQRO7HlcsBOa0WwvDJnRnskdyoD31s4F4jpKEYBJNWTo63v6lUv bQIDAQAB -----END PUBLIC KEY-----`, 2048, true}, {`-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvncDCeibmEkabJLmFec7 x9y86RP6dIvkVxxbQoOJo06E+p7tH6vCmiGHKnuuXwKYLq0DKUE3t/HHsNdowfD9 +NH8caLzmXqGBx45/Dzxnwqz0qYq7idK+Qff34qrk/YFoU7498U1Ee7PkKb7/VE9 BmMEcI3uoKbeXCbJRIHoTp8bUXOpNTSUfwUNwJzbm2nsHo2xu6virKtAZLTsJFzT UmRd11MrWCvj59lWzt1/eIMN+ekjH8aXeLOOl54CL+kWp48C+V9BchyKCShZB7uc imFvjHTtuxziXZQRO7HlcsBOa0WwvDJnRnskdyoD31s4F4jpKEYBJNWTo63v6lUv bQIDAQAB -----END PUBLIC KEY-----`, 4096, false}, } for i, test := range tests { actual := IsRsaPublicKey(test.rsastr, test.keylen) if actual != test.expected { t.Errorf("Expected TestIsRsaPublicKey(%d, %d) to be %v, got %v", i, test.keylen, test.expected, actual) } } } func TestIsRegex(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"^$", true}, {"$^", true}, {"^^", true}, {"$$", true}, {"a+", true}, {"a++", false}, {"a*", true}, {"a**", false}, {"a+*", false}, {"a*+", false}, {"[a+]+", true}, {"\\w+", true}, {"\\y+", false}, {"[asdf][qwer]", true}, {"[asdf[", false}, {"[asdf[]", true}, {"[asdf[][]", false}, {"(group2)(group3)", true}, {"(invalid_paranthesis(asdf)", false}, {"a?", true}, {"a??", true}, {"a???", false}, {"a\\???", true}, {"asdf\\/", true}, {"asdf/", true}, {"\\x61", true}, {"\\xg1", false}, {"\\x6h", false}, {"[asdf[", false}, {"[A-z]+", true}, {"[z-A]+", false}, {"[a-z-A]", true}, {"a{3,6}", true}, {"a{6,3|3,6}", true}, {"a{6,3}", false}, {"a|b", true}, {"a|b|", true}, {"a|b||", true}, //But false in python RE {"(?:)", true}, {"(?)", true}, //But false in python RE {"?", false}, {"(?::?)", true}, {"(?:?)", false}, {"(()?)", true}, {"(?:?)", false}, {"(A conditional matching)? (?(1)matched|not matched)", false}, //But true in python RE {"(A conditional matching)? (?(2)matched|not matched)", false}, {"(?:A conditional matching)? (?(1)matched|not matched)", false}, {"(?:[a-z]+)?", true}, {"(?#[a-z]+)?", false}, {"(?P[a-z]+)", true}, {"(?P>[a-z]+)", false}, } for _, test := range tests { actual := IsRegex(test.param) if actual != test.expected { t.Errorf("Expected IsNumeric(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsIMSI(t *testing.T) { tests := []struct { param string expected bool }{ {"234150999999999", true}, {"429011234567890", true}, {"310150123456789", true}, {"460001234567890", true}, {"4600012345678", false}, {"4600012345678901", false}, {"462001234567890", false}, {"1", false}, } for _, test := range tests { actual := IsIMSI(test.param) if actual != test.expected { t.Errorf("Expected IsIMSI(%q) to be %v, got %v", test.param, test.expected, actual) } } } func TestIsE164(t *testing.T) { t.Parallel() var tests = []struct { param string expected bool }{ {"+14155552671", true}, {"+442071838750", true}, {"+551155256325", true}, {"+226071234567 ", false}, {"+06071234567 ", false}, } for _, test := range tests { actual := IsE164(test.param) if actual != test.expected { t.Errorf("Expected IsURL(%q) to be %v, got %v", test.param, test.expected, actual) } } } govalidator-11.0.1/wercker.yml000066400000000000000000000003561402110523600162700ustar00rootroot00000000000000box: golang build: steps: - setup-go-workspace - script: name: go get code: | go version go get -t ./... - script: name: go test code: | go test -race -v ./...