pax_global_header00006660000000000000000000000064137426112260014516gustar00rootroot0000000000000052 comment=456221b630452990f72c0f13179e5f2ae728a723 validator-10.4.1/000077500000000000000000000000001374261122600135665ustar00rootroot00000000000000validator-10.4.1/.github/000077500000000000000000000000001374261122600151265ustar00rootroot00000000000000validator-10.4.1/.github/CONTRIBUTING.md000066400000000000000000000010441374261122600173560ustar00rootroot00000000000000# Contribution Guidelines ## Quality Standard To ensure the continued stability of this package, tests are required to be written or already exist in order for a pull request to be merged. ## Reporting issues Please open an issue or join the gitter chat [![Join the chat at https://gitter.im/go-playground/validator](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-playground/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) for any issues, questions or possible enhancements to the package. validator-10.4.1/.github/ISSUE_TEMPLATE.md000066400000000000000000000002021374261122600176250ustar00rootroot00000000000000### Package version eg. v8, v9: ### Issue, Question or Enhancement: ### Code sample, to showcase or reproduce: ```go ``` validator-10.4.1/.github/PULL_REQUEST_TEMPLATE.md000066400000000000000000000003331374261122600207260ustar00rootroot00000000000000Fixes Or Enhances # . **Make sure that you've checked the boxes below before you submit PR:** - [ ] Tests exist or have been written that cover this particular change. Change Details: - - - @go-playground/adminsvalidator-10.4.1/.gitignore000066400000000000000000000004701374261122600155570ustar00rootroot00000000000000# Compiled Object files, Static and Dynamic libs (Shared Objects) *.o *.a *.so # Folders _obj _test bin # Architecture specific extensions/prefixes *.[568vq] [568vq].out *.cgo1.go *.cgo2.c _cgo_defun.c _cgo_gotypes.go _cgo_export.* _testmain.go *.exe *.test *.prof *.test *.out *.txt cover.html README.html validator-10.4.1/.travis.yml000066400000000000000000000012171374261122600157000ustar00rootroot00000000000000language: go go: - 1.15.2 - tip matrix: allow_failures: - go: tip notifications: email: recipients: dean.karn@gmail.com on_success: change on_failure: always before_install: - go install github.com/mattn/goveralls - mkdir -p $GOPATH/src/gopkg.in - ln -s $GOPATH/src/github.com/$TRAVIS_REPO_SLUG $GOPATH/src/gopkg.in/validator.v9 # Only clone the most recent commit. git: depth: 1 script: - go test -v -race -covermode=atomic -coverprofile=coverage.coverprofile ./... after_success: | [ $TRAVIS_GO_VERSION = 1.15.2 ] && goveralls -coverprofile=coverage.coverprofile -service travis-ci -repotoken $COVERALLS_TOKEN validator-10.4.1/LICENSE000066400000000000000000000020651374261122600145760ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2015 Dean Karn 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. validator-10.4.1/Makefile000066400000000000000000000006371374261122600152340ustar00rootroot00000000000000GOCMD=GO111MODULE=on go linters-install: @golangci-lint --version >/dev/null 2>&1 || { \ echo "installing linting tools..."; \ curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s v1.21.0; \ } lint: linters-install $(PWD)/bin/golangci-lint run test: $(GOCMD) test -cover -race ./... bench: $(GOCMD) test -bench=. -benchmem ./... .PHONY: test lint linters-installvalidator-10.4.1/README.md000066400000000000000000000430351374261122600150520ustar00rootroot00000000000000Package validator ================ [![Join the chat at https://gitter.im/go-playground/validator](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-playground/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) ![Project status](https://img.shields.io/badge/version-10.4.1-green.svg) [![Build Status](https://travis-ci.org/go-playground/validator.svg?branch=master)](https://travis-ci.org/go-playground/validator) [![Coverage Status](https://coveralls.io/repos/go-playground/validator/badge.svg?branch=master&service=github)](https://coveralls.io/github/go-playground/validator?branch=master) [![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/validator)](https://goreportcard.com/report/github.com/go-playground/validator) [![GoDoc](https://godoc.org/github.com/go-playground/validator?status.svg)](https://pkg.go.dev/github.com/go-playground/validator/v10) ![License](https://img.shields.io/dub/l/vibe-d.svg) Package validator implements value validations for structs and individual fields based on tags. It has the following **unique** features: - Cross Field and Cross Struct validations by using validation tags or custom validators. - Slice, Array and Map diving, which allows any or all levels of a multidimensional field to be validated. - Ability to dive into both map keys and values for validation - Handles type interface by determining it's underlying type prior to validation. - Handles custom field types such as sql driver Valuer see [Valuer](https://golang.org/src/database/sql/driver/types.go?s=1210:1293#L29) - Alias validation tags, which allows for mapping of several validations to a single tag for easier defining of validations on structs - Extraction of custom defined Field Name e.g. can specify to extract the JSON name while validating and have it available in the resulting FieldError - Customizable i18n aware error messages. - Default validator for the [gin](https://github.com/gin-gonic/gin) web framework; upgrading from v8 to v9 in gin see [here](https://github.com/go-playground/validator/tree/master/_examples/gin-upgrading-overriding) Installation ------------ Use go get. go get github.com/go-playground/validator/v10 Then import the validator package into your own code. import "github.com/go-playground/validator/v10" Error Return Value ------- Validation functions return type error They return type error to avoid the issue discussed in the following, where err is always != nil: * http://stackoverflow.com/a/29138676/3158232 * https://github.com/go-playground/validator/issues/134 Validator only InvalidValidationError for bad validation input, nil or ValidationErrors as type error; so, in your code all you need to do is check if the error returned is not nil, and if it's not check if error is InvalidValidationError ( if necessary, most of the time it isn't ) type cast it to type ValidationErrors like so: ```go err := validate.Struct(mystruct) validationErrors := err.(validator.ValidationErrors) ``` Usage and documentation ------ Please see https://godoc.org/github.com/go-playground/validator for detailed usage docs. ##### Examples: - [Simple](https://github.com/go-playground/validator/blob/master/_examples/simple/main.go) - [Custom Field Types](https://github.com/go-playground/validator/blob/master/_examples/custom/main.go) - [Struct Level](https://github.com/go-playground/validator/blob/master/_examples/struct-level/main.go) - [Translations & Custom Errors](https://github.com/go-playground/validator/blob/master/_examples/translations/main.go) - [Gin upgrade and/or override validator](https://github.com/go-playground/validator/tree/v9/_examples/gin-upgrading-overriding) - [wash - an example application putting it all together](https://github.com/bluesuncorp/wash) Baked-in Validations ------ ### Fields: | Tag | Description | | - | - | | eqcsfield | Field Equals Another Field (relative)| | eqfield | Field Equals Another Field | | fieldcontains | NOT DOCUMENTED IN doc.go | | fieldexcludes | NOT DOCUMENTED IN doc.go | | gtcsfield | Field Greater Than Another Relative Field | | gtecsfield | Field Greater Than or Equal To Another Relative Field | | gtefield | Field Greater Than or Equal To Another Field | | gtfield | Field Greater Than Another Field | | ltcsfield | Less Than Another Relative Field | | ltecsfield | Less Than or Equal To Another Relative Field | | ltefield | Less Than or Equal To Another Field | | ltfield | Less Than Another Field | | necsfield | Field Does Not Equal Another Field (relative) | | nefield | Field Does Not Equal Another Field | ### Network: | Tag | Description | | - | - | | cidr | Classless Inter-Domain Routing CIDR | | cidrv4 | Classless Inter-Domain Routing CIDRv4 | | cidrv6 | Classless Inter-Domain Routing CIDRv6 | | datauri | Data URL | | fqdn | Full Qualified Domain Name (FQDN) | | hostname | Hostname RFC 952 | | hostname_port | HostPort | | hostname_rfc1123 | Hostname RFC 1123 | | ip | Internet Protocol Address IP | | ip4_addr | Internet Protocol Address IPv4 | | ip6_addr |Internet Protocol Address IPv6 | | ip_addr | Internet Protocol Address IP | | ipv4 | Internet Protocol Address IPv4 | | ipv6 | Internet Protocol Address IPv6 | | mac | Media Access Control Address MAC | | tcp4_addr | Transmission Control Protocol Address TCPv4 | | tcp6_addr | Transmission Control Protocol Address TCPv6 | | tcp_addr | Transmission Control Protocol Address TCP | | udp4_addr | User Datagram Protocol Address UDPv4 | | udp6_addr | User Datagram Protocol Address UDPv6 | | udp_addr | User Datagram Protocol Address UDP | | unix_addr | Unix domain socket end point Address | | uri | URI String | | url | URL String | | url_encoded | URL Encoded | | urn_rfc2141 | Urn RFC 2141 String | ### Strings: | Tag | Description | | - | - | | alpha | Alpha Only | | alphanum | Alphanumeric | | alphanumunicode | Alphanumeric Unicode | | alphaunicode | Alpha Unicode | | ascii | ASCII | | contains | Contains | | containsany | Contains Any | | containsrune | Contains Rune | | endswith | Ends With | | lowercase | Lowercase | | multibyte | Multi-Byte Characters | | number | NOT DOCUMENTED IN doc.go | | numeric | Numeric | | printascii | Printable ASCII | | startswith | Starts With | | uppercase | Uppercase | ### Format: | Tag | Description | | - | - | | base64 | Base64 String | | base64url | Base64URL String | | btc_addr | Bitcoin Address | | btc_addr_bech32 | Bitcoin Bech32 Address (segwit) | | datetime | Datetime | | e164 | e164 formatted phone number | | email | E-mail String | eth_addr | Ethereum Address | | hexadecimal | Hexadecimal String | | hexcolor | Hexcolor String | | hsl | HSL String | | hsla | HSLA String | | html | HTML Tags | | html_encoded | HTML Encoded | | isbn | International Standard Book Number | | isbn10 | International Standard Book Number 10 | | isbn13 | International Standard Book Number 13 | | json | JSON | | latitude | Latitude | | longitude | Longitude | | rgb | RGB String | | rgba | RGBA String | | ssn | Social Security Number SSN | | uuid | Universally Unique Identifier UUID | | uuid3 | Universally Unique Identifier UUID v3 | | uuid3_rfc4122 | Universally Unique Identifier UUID v3 RFC4122 | | uuid4 | Universally Unique Identifier UUID v4 | | uuid4_rfc4122 | Universally Unique Identifier UUID v4 RFC4122 | | uuid5 | Universally Unique Identifier UUID v5 | | uuid5_rfc4122 | Universally Unique Identifier UUID v5 RFC4122 | | uuid_rfc4122 | Universally Unique Identifier UUID RFC4122 | ### Comparisons: | Tag | Description | | - | - | | eq | Equals | | gt | Greater than| | gte |Greater than or equal | | lt | Less Than | | lte | Less Than or Equal | | ne | Not Equal | ### Other: | Tag | Description | | - | - | | dir | Directory | | endswith | Ends With | | excludes | Excludes | | excludesall | Excludes All | | excludesrune | Excludes Rune | | file | File path | | isdefault | Is Default | | len | Length | | max | Maximum | | min | Minimum | | oneof | One Of | | required | Required | | required_if | Required If | | required_unless | Required Unless | | required_with | Required With | | required_with_all | Required With All | | required_without | Required Without | | required_without_all | Required Without All | | excluded_with | Excluded With | | excluded_with_all | Excluded With All | | excluded_without | Excluded Without | | excluded_without_all | Excluded Without All | | unique | Unique | Benchmarks ------ ###### Run on MacBook Pro (15-inch, 2017) go version go1.10.2 darwin/amd64 ```go goos: darwin goarch: amd64 pkg: github.com/go-playground/validator BenchmarkFieldSuccess-8 20000000 83.6 ns/op 0 B/op 0 allocs/op BenchmarkFieldSuccessParallel-8 50000000 26.8 ns/op 0 B/op 0 allocs/op BenchmarkFieldFailure-8 5000000 291 ns/op 208 B/op 4 allocs/op BenchmarkFieldFailureParallel-8 20000000 107 ns/op 208 B/op 4 allocs/op BenchmarkFieldArrayDiveSuccess-8 2000000 623 ns/op 201 B/op 11 allocs/op BenchmarkFieldArrayDiveSuccessParallel-8 10000000 237 ns/op 201 B/op 11 allocs/op BenchmarkFieldArrayDiveFailure-8 2000000 859 ns/op 412 B/op 16 allocs/op BenchmarkFieldArrayDiveFailureParallel-8 5000000 335 ns/op 413 B/op 16 allocs/op BenchmarkFieldMapDiveSuccess-8 1000000 1292 ns/op 432 B/op 18 allocs/op BenchmarkFieldMapDiveSuccessParallel-8 3000000 467 ns/op 432 B/op 18 allocs/op BenchmarkFieldMapDiveFailure-8 1000000 1082 ns/op 512 B/op 16 allocs/op BenchmarkFieldMapDiveFailureParallel-8 5000000 425 ns/op 512 B/op 16 allocs/op BenchmarkFieldMapDiveWithKeysSuccess-8 1000000 1539 ns/op 480 B/op 21 allocs/op BenchmarkFieldMapDiveWithKeysSuccessParallel-8 3000000 613 ns/op 480 B/op 21 allocs/op BenchmarkFieldMapDiveWithKeysFailure-8 1000000 1413 ns/op 721 B/op 21 allocs/op BenchmarkFieldMapDiveWithKeysFailureParallel-8 3000000 575 ns/op 721 B/op 21 allocs/op BenchmarkFieldCustomTypeSuccess-8 10000000 216 ns/op 32 B/op 2 allocs/op BenchmarkFieldCustomTypeSuccessParallel-8 20000000 82.2 ns/op 32 B/op 2 allocs/op BenchmarkFieldCustomTypeFailure-8 5000000 274 ns/op 208 B/op 4 allocs/op BenchmarkFieldCustomTypeFailureParallel-8 20000000 116 ns/op 208 B/op 4 allocs/op BenchmarkFieldOrTagSuccess-8 2000000 740 ns/op 16 B/op 1 allocs/op BenchmarkFieldOrTagSuccessParallel-8 3000000 474 ns/op 16 B/op 1 allocs/op BenchmarkFieldOrTagFailure-8 3000000 471 ns/op 224 B/op 5 allocs/op BenchmarkFieldOrTagFailureParallel-8 3000000 414 ns/op 224 B/op 5 allocs/op BenchmarkStructLevelValidationSuccess-8 10000000 213 ns/op 32 B/op 2 allocs/op BenchmarkStructLevelValidationSuccessParallel-8 20000000 91.8 ns/op 32 B/op 2 allocs/op BenchmarkStructLevelValidationFailure-8 3000000 473 ns/op 304 B/op 8 allocs/op BenchmarkStructLevelValidationFailureParallel-8 10000000 234 ns/op 304 B/op 8 allocs/op BenchmarkStructSimpleCustomTypeSuccess-8 5000000 385 ns/op 32 B/op 2 allocs/op BenchmarkStructSimpleCustomTypeSuccessParallel-8 10000000 161 ns/op 32 B/op 2 allocs/op BenchmarkStructSimpleCustomTypeFailure-8 2000000 640 ns/op 424 B/op 9 allocs/op BenchmarkStructSimpleCustomTypeFailureParallel-8 5000000 318 ns/op 440 B/op 10 allocs/op BenchmarkStructFilteredSuccess-8 2000000 597 ns/op 288 B/op 9 allocs/op BenchmarkStructFilteredSuccessParallel-8 10000000 266 ns/op 288 B/op 9 allocs/op BenchmarkStructFilteredFailure-8 3000000 454 ns/op 256 B/op 7 allocs/op BenchmarkStructFilteredFailureParallel-8 10000000 214 ns/op 256 B/op 7 allocs/op BenchmarkStructPartialSuccess-8 3000000 502 ns/op 256 B/op 6 allocs/op BenchmarkStructPartialSuccessParallel-8 10000000 225 ns/op 256 B/op 6 allocs/op BenchmarkStructPartialFailure-8 2000000 702 ns/op 480 B/op 11 allocs/op BenchmarkStructPartialFailureParallel-8 5000000 329 ns/op 480 B/op 11 allocs/op BenchmarkStructExceptSuccess-8 2000000 793 ns/op 496 B/op 12 allocs/op BenchmarkStructExceptSuccessParallel-8 10000000 193 ns/op 240 B/op 5 allocs/op BenchmarkStructExceptFailure-8 2000000 639 ns/op 464 B/op 10 allocs/op BenchmarkStructExceptFailureParallel-8 5000000 300 ns/op 464 B/op 10 allocs/op BenchmarkStructSimpleCrossFieldSuccess-8 3000000 417 ns/op 72 B/op 3 allocs/op BenchmarkStructSimpleCrossFieldSuccessParallel-8 10000000 163 ns/op 72 B/op 3 allocs/op BenchmarkStructSimpleCrossFieldFailure-8 2000000 645 ns/op 304 B/op 8 allocs/op BenchmarkStructSimpleCrossFieldFailureParallel-8 5000000 285 ns/op 304 B/op 8 allocs/op BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 3000000 588 ns/op 80 B/op 4 allocs/op BenchmarkStructSimpleCrossStructCrossFieldSuccessParallel-8 10000000 221 ns/op 80 B/op 4 allocs/op BenchmarkStructSimpleCrossStructCrossFieldFailure-8 2000000 868 ns/op 320 B/op 9 allocs/op BenchmarkStructSimpleCrossStructCrossFieldFailureParallel-8 5000000 337 ns/op 320 B/op 9 allocs/op BenchmarkStructSimpleSuccess-8 5000000 260 ns/op 0 B/op 0 allocs/op BenchmarkStructSimpleSuccessParallel-8 20000000 90.6 ns/op 0 B/op 0 allocs/op BenchmarkStructSimpleFailure-8 2000000 619 ns/op 424 B/op 9 allocs/op BenchmarkStructSimpleFailureParallel-8 5000000 296 ns/op 424 B/op 9 allocs/op BenchmarkStructComplexSuccess-8 1000000 1454 ns/op 128 B/op 8 allocs/op BenchmarkStructComplexSuccessParallel-8 3000000 579 ns/op 128 B/op 8 allocs/op BenchmarkStructComplexFailure-8 300000 4140 ns/op 3041 B/op 53 allocs/op BenchmarkStructComplexFailureParallel-8 1000000 2127 ns/op 3041 B/op 53 allocs/op BenchmarkOneof-8 10000000 140 ns/op 0 B/op 0 allocs/op BenchmarkOneofParallel-8 20000000 70.1 ns/op 0 B/op 0 allocs/op ``` Complementary Software ---------------------- Here is a list of software that complements using this library either pre or post validation. * [form](https://github.com/go-playground/form) - Decodes url.Values into Go value(s) and Encodes Go value(s) into url.Values. Dual Array and Full map support. * [mold](https://github.com/go-playground/mold) - A general library to help modify or set data within data structures and other objects How to Contribute ------ Make a pull request... License ------ Distributed under MIT License, please see license file within the code for more details. validator-10.4.1/_examples/000077500000000000000000000000001374261122600155435ustar00rootroot00000000000000validator-10.4.1/_examples/custom-validation/000077500000000000000000000000001374261122600212055ustar00rootroot00000000000000validator-10.4.1/_examples/custom-validation/main.go000066400000000000000000000013171374261122600224620ustar00rootroot00000000000000package main import ( "fmt" "github.com/go-playground/validator/v10" ) // MyStruct .. type MyStruct struct { String string `validate:"is-awesome"` } // use a single instance of Validate, it caches struct info var validate *validator.Validate func main() { validate = validator.New() validate.RegisterValidation("is-awesome", ValidateMyVal) s := MyStruct{String: "awesome"} err := validate.Struct(s) if err != nil { fmt.Printf("Err(s):\n%+v\n", err) } s.String = "not awesome" err = validate.Struct(s) if err != nil { fmt.Printf("Err(s):\n%+v\n", err) } } // ValidateMyVal implements validator.Func func ValidateMyVal(fl validator.FieldLevel) bool { return fl.Field().String() == "awesome" } validator-10.4.1/_examples/custom/000077500000000000000000000000001374261122600170555ustar00rootroot00000000000000validator-10.4.1/_examples/custom/main.go000066400000000000000000000021371374261122600203330ustar00rootroot00000000000000package main import ( "database/sql" "database/sql/driver" "fmt" "reflect" "github.com/go-playground/validator/v10" ) // DbBackedUser User struct type DbBackedUser struct { Name sql.NullString `validate:"required"` Age sql.NullInt64 `validate:"required"` } // use a single instance of Validate, it caches struct info var validate *validator.Validate func main() { validate = validator.New() // register all sql.Null* types to use the ValidateValuer CustomTypeFunc validate.RegisterCustomTypeFunc(ValidateValuer, sql.NullString{}, sql.NullInt64{}, sql.NullBool{}, sql.NullFloat64{}) // build object for validation x := DbBackedUser{Name: sql.NullString{String: "", Valid: true}, Age: sql.NullInt64{Int64: 0, Valid: false}} err := validate.Struct(x) if err != nil { fmt.Printf("Err(s):\n%+v\n", err) } } // ValidateValuer implements validator.CustomTypeFunc func ValidateValuer(field reflect.Value) interface{} { if valuer, ok := field.Interface().(driver.Valuer); ok { val, err := valuer.Value() if err == nil { return val } // handle the error how you want } return nil } validator-10.4.1/_examples/dive/000077500000000000000000000000001374261122600164725ustar00rootroot00000000000000validator-10.4.1/_examples/dive/main.go000066400000000000000000000014001374261122600177400ustar00rootroot00000000000000package main import ( "fmt" "github.com/go-playground/validator/v10" ) // Test ... type Test struct { Array []string `validate:"required,gt=0,dive,required"` Map map[string]string `validate:"required,gt=0,dive,keys,keymax,endkeys,required,max=1000"` } // use a single instance of Validate, it caches struct info var validate *validator.Validate func main() { validate = validator.New() // registering alias so we can see the differences between // map key, value validation errors validate.RegisterAlias("keymax", "max=10") var test Test val(test) test.Array = []string{""} test.Map = map[string]string{"test > than 10": ""} val(test) } func val(test Test) { fmt.Println("testing") err := validate.Struct(test) fmt.Println(err) } validator-10.4.1/_examples/gin-upgrading-overriding/000077500000000000000000000000001374261122600224445ustar00rootroot00000000000000validator-10.4.1/_examples/gin-upgrading-overriding/main.go000066400000000000000000000002141374261122600237140ustar00rootroot00000000000000package main import "github.com/gin-gonic/gin/binding" func main() { binding.Validator = new(defaultValidator) // regular gin logic } validator-10.4.1/_examples/gin-upgrading-overriding/v8_to_v9.go000066400000000000000000000016441374261122600244550ustar00rootroot00000000000000package main import ( "reflect" "sync" "github.com/gin-gonic/gin/binding" "github.com/go-playground/validator/v10" ) type defaultValidator struct { once sync.Once validate *validator.Validate } var _ binding.StructValidator = &defaultValidator{} func (v *defaultValidator) ValidateStruct(obj interface{}) error { if kindOfData(obj) == reflect.Struct { v.lazyinit() if err := v.validate.Struct(obj); err != nil { return err } } return nil } func (v *defaultValidator) Engine() interface{} { v.lazyinit() return v.validate } func (v *defaultValidator) lazyinit() { v.once.Do(func() { v.validate = validator.New() v.validate.SetTagName("binding") // add any custom validations etc. here }) } func kindOfData(data interface{}) reflect.Kind { value := reflect.ValueOf(data) valueType := value.Kind() if valueType == reflect.Ptr { valueType = value.Elem().Kind() } return valueType } validator-10.4.1/_examples/simple/000077500000000000000000000000001374261122600170345ustar00rootroot00000000000000validator-10.4.1/_examples/simple/main.go000066400000000000000000000046031374261122600203120ustar00rootroot00000000000000package main import ( "fmt" "github.com/go-playground/validator/v10" ) // User contains user information type User struct { FirstName string `validate:"required"` LastName string `validate:"required"` Age uint8 `validate:"gte=0,lte=130"` Email string `validate:"required,email"` FavouriteColor string `validate:"iscolor"` // alias for 'hexcolor|rgb|rgba|hsl|hsla' Addresses []*Address `validate:"required,dive,required"` // a person can have a home and cottage... } // Address houses a users address information type Address struct { Street string `validate:"required"` City string `validate:"required"` Planet string `validate:"required"` Phone string `validate:"required"` } // use a single instance of Validate, it caches struct info var validate *validator.Validate func main() { validate = validator.New() validateStruct() validateVariable() } func validateStruct() { address := &Address{ Street: "Eavesdown Docks", Planet: "Persphone", Phone: "none", } user := &User{ FirstName: "Badger", LastName: "Smith", Age: 135, Email: "Badger.Smith@gmail.com", FavouriteColor: "#000-", Addresses: []*Address{address}, } // returns nil or ValidationErrors ( []FieldError ) err := validate.Struct(user) if err != nil { // this check is only needed when your code could produce // an invalid value for validation such as interface with nil // value most including myself do not usually have code like this. if _, ok := err.(*validator.InvalidValidationError); ok { fmt.Println(err) return } for _, err := range err.(validator.ValidationErrors) { fmt.Println(err.Namespace()) fmt.Println(err.Field()) fmt.Println(err.StructNamespace()) fmt.Println(err.StructField()) fmt.Println(err.Tag()) fmt.Println(err.ActualTag()) fmt.Println(err.Kind()) fmt.Println(err.Type()) fmt.Println(err.Value()) fmt.Println(err.Param()) fmt.Println() } // from here you can create your own error messages in whatever language you wish return } // save user to database } func validateVariable() { myEmail := "joeybloggs.gmail.com" errs := validate.Var(myEmail, "required,email") if errs != nil { fmt.Println(errs) // output: Key: "" Error:Field validation for "" failed on the "email" tag return } // email ok, move on } validator-10.4.1/_examples/struct-level/000077500000000000000000000000001374261122600201745ustar00rootroot00000000000000validator-10.4.1/_examples/struct-level/main.go000066400000000000000000000072431374261122600214550ustar00rootroot00000000000000package main import ( "fmt" "reflect" "strings" "github.com/go-playground/validator/v10" ) // User contains user information type User struct { FirstName string `json:"fname"` LastName string `json:"lname"` Age uint8 `validate:"gte=0,lte=130"` Email string `json:"e-mail" validate:"required,email"` FavouriteColor string `validate:"hexcolor|rgb|rgba"` Addresses []*Address `validate:"required,dive,required"` // a person can have a home and cottage... } // Address houses a users address information type Address struct { Street string `validate:"required"` City string `validate:"required"` Planet string `validate:"required"` Phone string `validate:"required"` } // use a single instance of Validate, it caches struct info var validate *validator.Validate func main() { validate = validator.New() // register function to get tag name from json tags. validate.RegisterTagNameFunc(func(fld reflect.StructField) string { name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] if name == "-" { return "" } return name }) // register validation for 'User' // NOTE: only have to register a non-pointer type for 'User', validator // interanlly dereferences during it's type checks. validate.RegisterStructValidation(UserStructLevelValidation, User{}) // build 'User' info, normally posted data etc... address := &Address{ Street: "Eavesdown Docks", Planet: "Persphone", Phone: "none", City: "Unknown", } user := &User{ FirstName: "", LastName: "", Age: 45, Email: "Badger.Smith@gmail", FavouriteColor: "#000", Addresses: []*Address{address}, } // returns InvalidValidationError for bad validation input, nil or ValidationErrors ( []FieldError ) err := validate.Struct(user) if err != nil { // this check is only needed when your code could produce // an invalid value for validation such as interface with nil // value most including myself do not usually have code like this. if _, ok := err.(*validator.InvalidValidationError); ok { fmt.Println(err) return } for _, err := range err.(validator.ValidationErrors) { fmt.Println(err.Namespace()) // can differ when a custom TagNameFunc is registered or fmt.Println(err.Field()) // by passing alt name to ReportError like below fmt.Println(err.StructNamespace()) fmt.Println(err.StructField()) fmt.Println(err.Tag()) fmt.Println(err.ActualTag()) fmt.Println(err.Kind()) fmt.Println(err.Type()) fmt.Println(err.Value()) fmt.Println(err.Param()) fmt.Println() } // from here you can create your own error messages in whatever language you wish return } // save user to database } // UserStructLevelValidation contains custom struct level validations that don't always // make sense at the field validation level. For Example this function validates that either // FirstName or LastName exist; could have done that with a custom field validation but then // would have had to add it to both fields duplicating the logic + overhead, this way it's // only validated once. // // NOTE: you may ask why wouldn't I just do this outside of validator, because doing this way // hooks right into validator and you can combine with validation tags and still have a // common error output format. func UserStructLevelValidation(sl validator.StructLevel) { user := sl.Current().Interface().(User) if len(user.FirstName) == 0 && len(user.LastName) == 0 { sl.ReportError(user.FirstName, "fname", "FirstName", "fnameorlname", "") sl.ReportError(user.LastName, "lname", "LastName", "fnameorlname", "") } // plus can do more, even with different tag than "fnameorlname" } validator-10.4.1/_examples/translations/000077500000000000000000000000001374261122600202645ustar00rootroot00000000000000validator-10.4.1/_examples/translations/main.go000066400000000000000000000062061374261122600215430ustar00rootroot00000000000000package main import ( "fmt" "github.com/go-playground/locales/en" ut "github.com/go-playground/universal-translator" "github.com/go-playground/validator/v10" en_translations "github.com/go-playground/validator/v10/translations/en" ) // User contains user information type User struct { FirstName string `validate:"required"` LastName string `validate:"required"` Age uint8 `validate:"gte=0,lte=130"` Email string `validate:"required,email"` FavouriteColor string `validate:"iscolor"` // alias for 'hexcolor|rgb|rgba|hsl|hsla' Addresses []*Address `validate:"required,dive,required"` // a person can have a home and cottage... } // Address houses a users address information type Address struct { Street string `validate:"required"` City string `validate:"required"` Planet string `validate:"required"` Phone string `validate:"required"` } // use a single instance , it caches struct info var ( uni *ut.UniversalTranslator validate *validator.Validate ) func main() { // NOTE: ommitting allot of error checking for brevity en := en.New() uni = ut.New(en, en) // this is usually know or extracted from http 'Accept-Language' header // also see uni.FindTranslator(...) trans, _ := uni.GetTranslator("en") validate = validator.New() en_translations.RegisterDefaultTranslations(validate, trans) translateAll(trans) translateIndividual(trans) translateOverride(trans) // yep you can specify your own in whatever locale you want! } func translateAll(trans ut.Translator) { type User struct { Username string `validate:"required"` Tagline string `validate:"required,lt=10"` Tagline2 string `validate:"required,gt=1"` } user := User{ Username: "Joeybloggs", Tagline: "This tagline is way too long.", Tagline2: "1", } err := validate.Struct(user) if err != nil { // translate all error at once errs := err.(validator.ValidationErrors) // returns a map with key = namespace & value = translated error // NOTICE: 2 errors are returned and you'll see something surprising // translations are i18n aware!!!! // eg. '10 characters' vs '1 character' fmt.Println(errs.Translate(trans)) } } func translateIndividual(trans ut.Translator) { type User struct { Username string `validate:"required"` } var user User err := validate.Struct(user) if err != nil { errs := err.(validator.ValidationErrors) for _, e := range errs { // can translate each error one at a time. fmt.Println(e.Translate(trans)) } } } func translateOverride(trans ut.Translator) { validate.RegisterTranslation("required", trans, func(ut ut.Translator) error { return ut.Add("required", "{0} must have a value!", true) // see universal-translator for details }, func(ut ut.Translator, fe validator.FieldError) string { t, _ := ut.T("required", fe.Field()) return t }) type User struct { Username string `validate:"required"` } var user User err := validate.Struct(user) if err != nil { errs := err.(validator.ValidationErrors) for _, e := range errs { // can translate each error one at a time. fmt.Println(e.Translate(trans)) } } } validator-10.4.1/baked_in.go000066400000000000000000001740201374261122600156550ustar00rootroot00000000000000package validator import ( "bytes" "context" "crypto/sha256" "encoding/hex" "encoding/json" "fmt" "net" "net/url" "os" "reflect" "strconv" "strings" "sync" "time" "unicode/utf8" "golang.org/x/crypto/sha3" urn "github.com/leodido/go-urn" ) // Func accepts a FieldLevel interface for all validation needs. The return // value should be true when validation succeeds. type Func func(fl FieldLevel) bool // FuncCtx accepts a context.Context and FieldLevel interface for all // validation needs. The return value should be true when validation succeeds. type FuncCtx func(ctx context.Context, fl FieldLevel) bool // wrapFunc wraps noramal Func makes it compatible with FuncCtx func wrapFunc(fn Func) FuncCtx { if fn == nil { return nil // be sure not to wrap a bad function. } return func(ctx context.Context, fl FieldLevel) bool { return fn(fl) } } var ( restrictedTags = map[string]struct{}{ diveTag: {}, keysTag: {}, endKeysTag: {}, structOnlyTag: {}, omitempty: {}, skipValidationTag: {}, utf8HexComma: {}, utf8Pipe: {}, noStructLevelTag: {}, requiredTag: {}, isdefault: {}, } // BakedInAliasValidators is a default mapping of a single validation tag that // defines a common or complex set of validation(s) to simplify // adding validation to structs. bakedInAliases = map[string]string{ "iscolor": "hexcolor|rgb|rgba|hsl|hsla", "country_code": "iso3166_1_alpha2|iso3166_1_alpha3|iso3166_1_alpha_numeric", } // BakedInValidators is the default map of ValidationFunc // you can add, remove or even replace items to suite your needs, // or even disregard and use your own map if so desired. bakedInValidators = map[string]Func{ "required": hasValue, "required_if": requiredIf, "required_unless": requiredUnless, "required_with": requiredWith, "required_with_all": requiredWithAll, "required_without": requiredWithout, "required_without_all": requiredWithoutAll, "excluded_with": excludedWith, "excluded_with_all": excludedWithAll, "excluded_without": excludedWithout, "excluded_without_all": excludedWithoutAll, "isdefault": isDefault, "len": hasLengthOf, "min": hasMinOf, "max": hasMaxOf, "eq": isEq, "ne": isNe, "lt": isLt, "lte": isLte, "gt": isGt, "gte": isGte, "eqfield": isEqField, "eqcsfield": isEqCrossStructField, "necsfield": isNeCrossStructField, "gtcsfield": isGtCrossStructField, "gtecsfield": isGteCrossStructField, "ltcsfield": isLtCrossStructField, "ltecsfield": isLteCrossStructField, "nefield": isNeField, "gtefield": isGteField, "gtfield": isGtField, "ltefield": isLteField, "ltfield": isLtField, "fieldcontains": fieldContains, "fieldexcludes": fieldExcludes, "alpha": isAlpha, "alphanum": isAlphanum, "alphaunicode": isAlphaUnicode, "alphanumunicode": isAlphanumUnicode, "numeric": isNumeric, "number": isNumber, "hexadecimal": isHexadecimal, "hexcolor": isHEXColor, "rgb": isRGB, "rgba": isRGBA, "hsl": isHSL, "hsla": isHSLA, "e164": isE164, "email": isEmail, "url": isURL, "uri": isURI, "urn_rfc2141": isUrnRFC2141, // RFC 2141 "file": isFile, "base64": isBase64, "base64url": isBase64URL, "contains": contains, "containsany": containsAny, "containsrune": containsRune, "excludes": excludes, "excludesall": excludesAll, "excludesrune": excludesRune, "startswith": startsWith, "endswith": endsWith, "startsnotwith": startsNotWith, "endsnotwith": endsNotWith, "isbn": isISBN, "isbn10": isISBN10, "isbn13": isISBN13, "eth_addr": isEthereumAddress, "btc_addr": isBitcoinAddress, "btc_addr_bech32": isBitcoinBech32Address, "uuid": isUUID, "uuid3": isUUID3, "uuid4": isUUID4, "uuid5": isUUID5, "uuid_rfc4122": isUUIDRFC4122, "uuid3_rfc4122": isUUID3RFC4122, "uuid4_rfc4122": isUUID4RFC4122, "uuid5_rfc4122": isUUID5RFC4122, "ascii": isASCII, "printascii": isPrintableASCII, "multibyte": hasMultiByteCharacter, "datauri": isDataURI, "latitude": isLatitude, "longitude": isLongitude, "ssn": isSSN, "ipv4": isIPv4, "ipv6": isIPv6, "ip": isIP, "cidrv4": isCIDRv4, "cidrv6": isCIDRv6, "cidr": isCIDR, "tcp4_addr": isTCP4AddrResolvable, "tcp6_addr": isTCP6AddrResolvable, "tcp_addr": isTCPAddrResolvable, "udp4_addr": isUDP4AddrResolvable, "udp6_addr": isUDP6AddrResolvable, "udp_addr": isUDPAddrResolvable, "ip4_addr": isIP4AddrResolvable, "ip6_addr": isIP6AddrResolvable, "ip_addr": isIPAddrResolvable, "unix_addr": isUnixAddrResolvable, "mac": isMAC, "hostname": isHostnameRFC952, // RFC 952 "hostname_rfc1123": isHostnameRFC1123, // RFC 1123 "fqdn": isFQDN, "unique": isUnique, "oneof": isOneOf, "html": isHTML, "html_encoded": isHTMLEncoded, "url_encoded": isURLEncoded, "dir": isDir, "json": isJSON, "hostname_port": isHostnamePort, "lowercase": isLowercase, "uppercase": isUppercase, "datetime": isDatetime, "timezone": isTimeZone, "iso3166_1_alpha2": isIso3166Alpha2, "iso3166_1_alpha3": isIso3166Alpha3, "iso3166_1_alpha_numeric": isIso3166AlphaNumeric, } ) var oneofValsCache = map[string][]string{} var oneofValsCacheRWLock = sync.RWMutex{} func parseOneOfParam2(s string) []string { oneofValsCacheRWLock.RLock() vals, ok := oneofValsCache[s] oneofValsCacheRWLock.RUnlock() if !ok { oneofValsCacheRWLock.Lock() vals = splitParamsRegex.FindAllString(s, -1) for i := 0; i < len(vals); i++ { vals[i] = strings.Replace(vals[i], "'", "", -1) } oneofValsCache[s] = vals oneofValsCacheRWLock.Unlock() } return vals } func isURLEncoded(fl FieldLevel) bool { return uRLEncodedRegex.MatchString(fl.Field().String()) } func isHTMLEncoded(fl FieldLevel) bool { return hTMLEncodedRegex.MatchString(fl.Field().String()) } func isHTML(fl FieldLevel) bool { return hTMLRegex.MatchString(fl.Field().String()) } func isOneOf(fl FieldLevel) bool { vals := parseOneOfParam2(fl.Param()) field := fl.Field() var v string switch field.Kind() { case reflect.String: v = field.String() case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: v = strconv.FormatInt(field.Int(), 10) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: v = strconv.FormatUint(field.Uint(), 10) default: panic(fmt.Sprintf("Bad field type %T", field.Interface())) } for i := 0; i < len(vals); i++ { if vals[i] == v { return true } } return false } // isUnique is the validation function for validating if each array|slice|map value is unique func isUnique(fl FieldLevel) bool { field := fl.Field() param := fl.Param() v := reflect.ValueOf(struct{}{}) switch field.Kind() { case reflect.Slice, reflect.Array: elem := field.Type().Elem() if elem.Kind() == reflect.Ptr { elem = elem.Elem() } if param == "" { m := reflect.MakeMap(reflect.MapOf(elem, v.Type())) for i := 0; i < field.Len(); i++ { m.SetMapIndex(reflect.Indirect(field.Index(i)), v) } return field.Len() == m.Len() } sf, ok := elem.FieldByName(param) if !ok { panic(fmt.Sprintf("Bad field name %s", param)) } sfTyp := sf.Type if sfTyp.Kind() == reflect.Ptr { sfTyp = sfTyp.Elem() } m := reflect.MakeMap(reflect.MapOf(sfTyp, v.Type())) for i := 0; i < field.Len(); i++ { m.SetMapIndex(reflect.Indirect(reflect.Indirect(field.Index(i)).FieldByName(param)), v) } return field.Len() == m.Len() case reflect.Map: m := reflect.MakeMap(reflect.MapOf(field.Type().Elem(), v.Type())) for _, k := range field.MapKeys() { m.SetMapIndex(field.MapIndex(k), v) } return field.Len() == m.Len() default: panic(fmt.Sprintf("Bad field type %T", field.Interface())) } } // IsMAC is the validation function for validating if the field's value is a valid MAC address. func isMAC(fl FieldLevel) bool { _, err := net.ParseMAC(fl.Field().String()) return err == nil } // IsCIDRv4 is the validation function for validating if the field's value is a valid v4 CIDR address. func isCIDRv4(fl FieldLevel) bool { ip, _, err := net.ParseCIDR(fl.Field().String()) return err == nil && ip.To4() != nil } // IsCIDRv6 is the validation function for validating if the field's value is a valid v6 CIDR address. func isCIDRv6(fl FieldLevel) bool { ip, _, err := net.ParseCIDR(fl.Field().String()) return err == nil && ip.To4() == nil } // IsCIDR is the validation function for validating if the field's value is a valid v4 or v6 CIDR address. func isCIDR(fl FieldLevel) bool { _, _, err := net.ParseCIDR(fl.Field().String()) return err == nil } // IsIPv4 is the validation function for validating if a value is a valid v4 IP address. func isIPv4(fl FieldLevel) bool { ip := net.ParseIP(fl.Field().String()) return ip != nil && ip.To4() != nil } // IsIPv6 is the validation function for validating if the field's value is a valid v6 IP address. func isIPv6(fl FieldLevel) bool { ip := net.ParseIP(fl.Field().String()) return ip != nil && ip.To4() == nil } // IsIP is the validation function for validating if the field's value is a valid v4 or v6 IP address. func isIP(fl FieldLevel) bool { ip := net.ParseIP(fl.Field().String()) return ip != nil } // IsSSN is the validation function for validating if the field's value is a valid SSN. func isSSN(fl FieldLevel) bool { field := fl.Field() if field.Len() != 11 { return false } return sSNRegex.MatchString(field.String()) } // IsLongitude is the validation function for validating if the field's value is a valid longitude coordinate. func isLongitude(fl FieldLevel) bool { field := fl.Field() var v string switch field.Kind() { case reflect.String: v = field.String() case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: v = strconv.FormatInt(field.Int(), 10) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: v = strconv.FormatUint(field.Uint(), 10) case reflect.Float32: v = strconv.FormatFloat(field.Float(), 'f', -1, 32) case reflect.Float64: v = strconv.FormatFloat(field.Float(), 'f', -1, 64) default: panic(fmt.Sprintf("Bad field type %T", field.Interface())) } return longitudeRegex.MatchString(v) } // IsLatitude is the validation function for validating if the field's value is a valid latitude coordinate. func isLatitude(fl FieldLevel) bool { field := fl.Field() var v string switch field.Kind() { case reflect.String: v = field.String() case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: v = strconv.FormatInt(field.Int(), 10) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: v = strconv.FormatUint(field.Uint(), 10) case reflect.Float32: v = strconv.FormatFloat(field.Float(), 'f', -1, 32) case reflect.Float64: v = strconv.FormatFloat(field.Float(), 'f', -1, 64) default: panic(fmt.Sprintf("Bad field type %T", field.Interface())) } return latitudeRegex.MatchString(v) } // IsDataURI is the validation function for validating if the field's value is a valid data URI. func isDataURI(fl FieldLevel) bool { uri := strings.SplitN(fl.Field().String(), ",", 2) if len(uri) != 2 { return false } if !dataURIRegex.MatchString(uri[0]) { return false } return base64Regex.MatchString(uri[1]) } // HasMultiByteCharacter is the validation function for validating if the field's value has a multi byte character. func hasMultiByteCharacter(fl FieldLevel) bool { field := fl.Field() if field.Len() == 0 { return true } return multibyteRegex.MatchString(field.String()) } // IsPrintableASCII is the validation function for validating if the field's value is a valid printable ASCII character. func isPrintableASCII(fl FieldLevel) bool { return printableASCIIRegex.MatchString(fl.Field().String()) } // IsASCII is the validation function for validating if the field's value is a valid ASCII character. func isASCII(fl FieldLevel) bool { return aSCIIRegex.MatchString(fl.Field().String()) } // IsUUID5 is the validation function for validating if the field's value is a valid v5 UUID. func isUUID5(fl FieldLevel) bool { return uUID5Regex.MatchString(fl.Field().String()) } // IsUUID4 is the validation function for validating if the field's value is a valid v4 UUID. func isUUID4(fl FieldLevel) bool { return uUID4Regex.MatchString(fl.Field().String()) } // IsUUID3 is the validation function for validating if the field's value is a valid v3 UUID. func isUUID3(fl FieldLevel) bool { return uUID3Regex.MatchString(fl.Field().String()) } // IsUUID is the validation function for validating if the field's value is a valid UUID of any version. func isUUID(fl FieldLevel) bool { return uUIDRegex.MatchString(fl.Field().String()) } // IsUUID5RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v5 UUID. func isUUID5RFC4122(fl FieldLevel) bool { return uUID5RFC4122Regex.MatchString(fl.Field().String()) } // IsUUID4RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v4 UUID. func isUUID4RFC4122(fl FieldLevel) bool { return uUID4RFC4122Regex.MatchString(fl.Field().String()) } // IsUUID3RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v3 UUID. func isUUID3RFC4122(fl FieldLevel) bool { return uUID3RFC4122Regex.MatchString(fl.Field().String()) } // IsUUIDRFC4122 is the validation function for validating if the field's value is a valid RFC4122 UUID of any version. func isUUIDRFC4122(fl FieldLevel) bool { return uUIDRFC4122Regex.MatchString(fl.Field().String()) } // IsISBN is the validation function for validating if the field's value is a valid v10 or v13 ISBN. func isISBN(fl FieldLevel) bool { return isISBN10(fl) || isISBN13(fl) } // IsISBN13 is the validation function for validating if the field's value is a valid v13 ISBN. func isISBN13(fl FieldLevel) bool { s := strings.Replace(strings.Replace(fl.Field().String(), "-", "", 4), " ", "", 4) if !iSBN13Regex.MatchString(s) { return false } var checksum int32 var i int32 factor := []int32{1, 3} for i = 0; i < 12; i++ { checksum += factor[i%2] * int32(s[i]-'0') } return (int32(s[12]-'0'))-((10-(checksum%10))%10) == 0 } // IsISBN10 is the validation function for validating if the field's value is a valid v10 ISBN. func isISBN10(fl FieldLevel) bool { s := strings.Replace(strings.Replace(fl.Field().String(), "-", "", 3), " ", "", 3) if !iSBN10Regex.MatchString(s) { return false } var checksum int32 var i int32 for i = 0; i < 9; i++ { checksum += (i + 1) * int32(s[i]-'0') } if s[9] == 'X' { checksum += 10 * 10 } else { checksum += 10 * int32(s[9]-'0') } return checksum%11 == 0 } // IsEthereumAddress is the validation function for validating if the field's value is a valid Ethereum address. func isEthereumAddress(fl FieldLevel) bool { address := fl.Field().String() if !ethAddressRegex.MatchString(address) { return false } if ethaddressRegexUpper.MatchString(address) || ethAddressRegexLower.MatchString(address) { return true } // Checksum validation. Reference: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md address = address[2:] // Skip "0x" prefix. h := sha3.NewLegacyKeccak256() // hash.Hash's io.Writer implementation says it never returns an error. https://golang.org/pkg/hash/#Hash _, _ = h.Write([]byte(strings.ToLower(address))) hash := hex.EncodeToString(h.Sum(nil)) for i := 0; i < len(address); i++ { if address[i] <= '9' { // Skip 0-9 digits: they don't have upper/lower-case. continue } if hash[i] > '7' && address[i] >= 'a' || hash[i] <= '7' && address[i] <= 'F' { return false } } return true } // IsBitcoinAddress is the validation function for validating if the field's value is a valid btc address func isBitcoinAddress(fl FieldLevel) bool { address := fl.Field().String() if !btcAddressRegex.MatchString(address) { return false } alphabet := []byte("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") decode := [25]byte{} for _, n := range []byte(address) { d := bytes.IndexByte(alphabet, n) for i := 24; i >= 0; i-- { d += 58 * int(decode[i]) decode[i] = byte(d % 256) d /= 256 } } h := sha256.New() _, _ = h.Write(decode[:21]) d := h.Sum([]byte{}) h = sha256.New() _, _ = h.Write(d) validchecksum := [4]byte{} computedchecksum := [4]byte{} copy(computedchecksum[:], h.Sum(d[:0])) copy(validchecksum[:], decode[21:]) return validchecksum == computedchecksum } // IsBitcoinBech32Address is the validation function for validating if the field's value is a valid bech32 btc address func isBitcoinBech32Address(fl FieldLevel) bool { address := fl.Field().String() if !btcLowerAddressRegexBech32.MatchString(address) && !btcUpperAddressRegexBech32.MatchString(address) { return false } am := len(address) % 8 if am == 0 || am == 3 || am == 5 { return false } address = strings.ToLower(address) alphabet := "qpzry9x8gf2tvdw0s3jn54khce6mua7l" hr := []int{3, 3, 0, 2, 3} // the human readable part will always be bc addr := address[3:] dp := make([]int, 0, len(addr)) for _, c := range addr { dp = append(dp, strings.IndexRune(alphabet, c)) } ver := dp[0] if ver < 0 || ver > 16 { return false } if ver == 0 { if len(address) != 42 && len(address) != 62 { return false } } values := append(hr, dp...) GEN := []int{0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3} p := 1 for _, v := range values { b := p >> 25 p = (p&0x1ffffff)<<5 ^ v for i := 0; i < 5; i++ { if (b>>uint(i))&1 == 1 { p ^= GEN[i] } } } if p != 1 { return false } b := uint(0) acc := 0 mv := (1 << 5) - 1 var sw []int for _, v := range dp[1 : len(dp)-6] { acc = (acc << 5) | v b += 5 for b >= 8 { b -= 8 sw = append(sw, (acc>>b)&mv) } } if len(sw) < 2 || len(sw) > 40 { return false } return true } // ExcludesRune is the validation function for validating that the field's value does not contain the rune specified within the param. func excludesRune(fl FieldLevel) bool { return !containsRune(fl) } // ExcludesAll is the validation function for validating that the field's value does not contain any of the characters specified within the param. func excludesAll(fl FieldLevel) bool { return !containsAny(fl) } // Excludes is the validation function for validating that the field's value does not contain the text specified within the param. func excludes(fl FieldLevel) bool { return !contains(fl) } // ContainsRune is the validation function for validating that the field's value contains the rune specified within the param. func containsRune(fl FieldLevel) bool { r, _ := utf8.DecodeRuneInString(fl.Param()) return strings.ContainsRune(fl.Field().String(), r) } // ContainsAny is the validation function for validating that the field's value contains any of the characters specified within the param. func containsAny(fl FieldLevel) bool { return strings.ContainsAny(fl.Field().String(), fl.Param()) } // Contains is the validation function for validating that the field's value contains the text specified within the param. func contains(fl FieldLevel) bool { return strings.Contains(fl.Field().String(), fl.Param()) } // StartsWith is the validation function for validating that the field's value starts with the text specified within the param. func startsWith(fl FieldLevel) bool { return strings.HasPrefix(fl.Field().String(), fl.Param()) } // EndsWith is the validation function for validating that the field's value ends with the text specified within the param. func endsWith(fl FieldLevel) bool { return strings.HasSuffix(fl.Field().String(), fl.Param()) } // StartsNotWith is the validation function for validating that the field's value does not start with the text specified within the param. func startsNotWith(fl FieldLevel) bool { return !startsWith(fl) } // EndsNotWith is the validation function for validating that the field's value does not end with the text specified within the param. func endsNotWith(fl FieldLevel) bool { return !endsWith(fl) } // FieldContains is the validation function for validating if the current field's value contains the field specified by the param's value. func fieldContains(fl FieldLevel) bool { field := fl.Field() currentField, _, ok := fl.GetStructFieldOK() if !ok { return false } return strings.Contains(field.String(), currentField.String()) } // FieldExcludes is the validation function for validating if the current field's value excludes the field specified by the param's value. func fieldExcludes(fl FieldLevel) bool { field := fl.Field() currentField, _, ok := fl.GetStructFieldOK() if !ok { return true } return !strings.Contains(field.String(), currentField.String()) } // IsNeField is the validation function for validating if the current field's value is not equal to the field specified by the param's value. func isNeField(fl FieldLevel) bool { field := fl.Field() kind := field.Kind() currentField, currentKind, ok := fl.GetStructFieldOK() if !ok || currentKind != kind { return true } switch kind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int() != currentField.Int() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return field.Uint() != currentField.Uint() case reflect.Float32, reflect.Float64: return field.Float() != currentField.Float() case reflect.Slice, reflect.Map, reflect.Array: return int64(field.Len()) != int64(currentField.Len()) case reflect.Struct: fieldType := field.Type() // Not Same underlying type i.e. struct and time if fieldType != currentField.Type() { return true } if fieldType == timeType { t := currentField.Interface().(time.Time) fieldTime := field.Interface().(time.Time) return !fieldTime.Equal(t) } } // default reflect.String: return field.String() != currentField.String() } // IsNe is the validation function for validating that the field's value does not equal the provided param value. func isNe(fl FieldLevel) bool { return !isEq(fl) } // IsLteCrossStructField is the validation function for validating if the current field's value is less than or equal to the field, within a separate struct, specified by the param's value. func isLteCrossStructField(fl FieldLevel) bool { field := fl.Field() kind := field.Kind() topField, topKind, ok := fl.GetStructFieldOK() if !ok || topKind != kind { return false } switch kind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int() <= topField.Int() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return field.Uint() <= topField.Uint() case reflect.Float32, reflect.Float64: return field.Float() <= topField.Float() case reflect.Slice, reflect.Map, reflect.Array: return int64(field.Len()) <= int64(topField.Len()) case reflect.Struct: fieldType := field.Type() // Not Same underlying type i.e. struct and time if fieldType != topField.Type() { return false } if fieldType == timeType { fieldTime := field.Interface().(time.Time) topTime := topField.Interface().(time.Time) return fieldTime.Before(topTime) || fieldTime.Equal(topTime) } } // default reflect.String: return field.String() <= topField.String() } // IsLtCrossStructField is the validation function for validating if the current field's value is less than the field, within a separate struct, specified by the param's value. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func isLtCrossStructField(fl FieldLevel) bool { field := fl.Field() kind := field.Kind() topField, topKind, ok := fl.GetStructFieldOK() if !ok || topKind != kind { return false } switch kind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int() < topField.Int() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return field.Uint() < topField.Uint() case reflect.Float32, reflect.Float64: return field.Float() < topField.Float() case reflect.Slice, reflect.Map, reflect.Array: return int64(field.Len()) < int64(topField.Len()) case reflect.Struct: fieldType := field.Type() // Not Same underlying type i.e. struct and time if fieldType != topField.Type() { return false } if fieldType == timeType { fieldTime := field.Interface().(time.Time) topTime := topField.Interface().(time.Time) return fieldTime.Before(topTime) } } // default reflect.String: return field.String() < topField.String() } // IsGteCrossStructField is the validation function for validating if the current field's value is greater than or equal to the field, within a separate struct, specified by the param's value. func isGteCrossStructField(fl FieldLevel) bool { field := fl.Field() kind := field.Kind() topField, topKind, ok := fl.GetStructFieldOK() if !ok || topKind != kind { return false } switch kind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int() >= topField.Int() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return field.Uint() >= topField.Uint() case reflect.Float32, reflect.Float64: return field.Float() >= topField.Float() case reflect.Slice, reflect.Map, reflect.Array: return int64(field.Len()) >= int64(topField.Len()) case reflect.Struct: fieldType := field.Type() // Not Same underlying type i.e. struct and time if fieldType != topField.Type() { return false } if fieldType == timeType { fieldTime := field.Interface().(time.Time) topTime := topField.Interface().(time.Time) return fieldTime.After(topTime) || fieldTime.Equal(topTime) } } // default reflect.String: return field.String() >= topField.String() } // IsGtCrossStructField is the validation function for validating if the current field's value is greater than the field, within a separate struct, specified by the param's value. func isGtCrossStructField(fl FieldLevel) bool { field := fl.Field() kind := field.Kind() topField, topKind, ok := fl.GetStructFieldOK() if !ok || topKind != kind { return false } switch kind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int() > topField.Int() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return field.Uint() > topField.Uint() case reflect.Float32, reflect.Float64: return field.Float() > topField.Float() case reflect.Slice, reflect.Map, reflect.Array: return int64(field.Len()) > int64(topField.Len()) case reflect.Struct: fieldType := field.Type() // Not Same underlying type i.e. struct and time if fieldType != topField.Type() { return false } if fieldType == timeType { fieldTime := field.Interface().(time.Time) topTime := topField.Interface().(time.Time) return fieldTime.After(topTime) } } // default reflect.String: return field.String() > topField.String() } // IsNeCrossStructField is the validation function for validating that the current field's value is not equal to the field, within a separate struct, specified by the param's value. func isNeCrossStructField(fl FieldLevel) bool { field := fl.Field() kind := field.Kind() topField, currentKind, ok := fl.GetStructFieldOK() if !ok || currentKind != kind { return true } switch kind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return topField.Int() != field.Int() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return topField.Uint() != field.Uint() case reflect.Float32, reflect.Float64: return topField.Float() != field.Float() case reflect.Slice, reflect.Map, reflect.Array: return int64(topField.Len()) != int64(field.Len()) case reflect.Struct: fieldType := field.Type() // Not Same underlying type i.e. struct and time if fieldType != topField.Type() { return true } if fieldType == timeType { t := field.Interface().(time.Time) fieldTime := topField.Interface().(time.Time) return !fieldTime.Equal(t) } } // default reflect.String: return topField.String() != field.String() } // IsEqCrossStructField is the validation function for validating that the current field's value is equal to the field, within a separate struct, specified by the param's value. func isEqCrossStructField(fl FieldLevel) bool { field := fl.Field() kind := field.Kind() topField, topKind, ok := fl.GetStructFieldOK() if !ok || topKind != kind { return false } switch kind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return topField.Int() == field.Int() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return topField.Uint() == field.Uint() case reflect.Float32, reflect.Float64: return topField.Float() == field.Float() case reflect.Slice, reflect.Map, reflect.Array: return int64(topField.Len()) == int64(field.Len()) case reflect.Struct: fieldType := field.Type() // Not Same underlying type i.e. struct and time if fieldType != topField.Type() { return false } if fieldType == timeType { t := field.Interface().(time.Time) fieldTime := topField.Interface().(time.Time) return fieldTime.Equal(t) } } // default reflect.String: return topField.String() == field.String() } // IsEqField is the validation function for validating if the current field's value is equal to the field specified by the param's value. func isEqField(fl FieldLevel) bool { field := fl.Field() kind := field.Kind() currentField, currentKind, ok := fl.GetStructFieldOK() if !ok || currentKind != kind { return false } switch kind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int() == currentField.Int() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return field.Uint() == currentField.Uint() case reflect.Float32, reflect.Float64: return field.Float() == currentField.Float() case reflect.Slice, reflect.Map, reflect.Array: return int64(field.Len()) == int64(currentField.Len()) case reflect.Struct: fieldType := field.Type() // Not Same underlying type i.e. struct and time if fieldType != currentField.Type() { return false } if fieldType == timeType { t := currentField.Interface().(time.Time) fieldTime := field.Interface().(time.Time) return fieldTime.Equal(t) } } // default reflect.String: return field.String() == currentField.String() } // IsEq is the validation function for validating if the current field's value is equal to the param's value. func isEq(fl FieldLevel) bool { field := fl.Field() param := fl.Param() switch field.Kind() { case reflect.String: return field.String() == param case reflect.Slice, reflect.Map, reflect.Array: p := asInt(param) return int64(field.Len()) == p case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: p := asIntFromType(field.Type(), param) return field.Int() == p case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: p := asUint(param) return field.Uint() == p case reflect.Float32, reflect.Float64: p := asFloat(param) return field.Float() == p case reflect.Bool: p := asBool(param) return field.Bool() == p } panic(fmt.Sprintf("Bad field type %T", field.Interface())) } // IsBase64 is the validation function for validating if the current field's value is a valid base 64. func isBase64(fl FieldLevel) bool { return base64Regex.MatchString(fl.Field().String()) } // IsBase64URL is the validation function for validating if the current field's value is a valid base64 URL safe string. func isBase64URL(fl FieldLevel) bool { return base64URLRegex.MatchString(fl.Field().String()) } // IsURI is the validation function for validating if the current field's value is a valid URI. func isURI(fl FieldLevel) bool { field := fl.Field() switch field.Kind() { case reflect.String: s := field.String() // checks needed as of Go 1.6 because of change https://github.com/golang/go/commit/617c93ce740c3c3cc28cdd1a0d712be183d0b328#diff-6c2d018290e298803c0c9419d8739885L195 // emulate browser and strip the '#' suffix prior to validation. see issue-#237 if i := strings.Index(s, "#"); i > -1 { s = s[:i] } if len(s) == 0 { return false } _, err := url.ParseRequestURI(s) return err == nil } panic(fmt.Sprintf("Bad field type %T", field.Interface())) } // IsURL is the validation function for validating if the current field's value is a valid URL. func isURL(fl FieldLevel) bool { field := fl.Field() switch field.Kind() { case reflect.String: var i int s := field.String() // checks needed as of Go 1.6 because of change https://github.com/golang/go/commit/617c93ce740c3c3cc28cdd1a0d712be183d0b328#diff-6c2d018290e298803c0c9419d8739885L195 // emulate browser and strip the '#' suffix prior to validation. see issue-#237 if i = strings.Index(s, "#"); i > -1 { s = s[:i] } if len(s) == 0 { return false } url, err := url.ParseRequestURI(s) if err != nil || url.Scheme == "" { return false } return true } panic(fmt.Sprintf("Bad field type %T", field.Interface())) } // isUrnRFC2141 is the validation function for validating if the current field's value is a valid URN as per RFC 2141. func isUrnRFC2141(fl FieldLevel) bool { field := fl.Field() switch field.Kind() { case reflect.String: str := field.String() _, match := urn.Parse([]byte(str)) return match } panic(fmt.Sprintf("Bad field type %T", field.Interface())) } // IsFile is the validation function for validating if the current field's value is a valid file path. func isFile(fl FieldLevel) bool { field := fl.Field() switch field.Kind() { case reflect.String: fileInfo, err := os.Stat(field.String()) if err != nil { return false } return !fileInfo.IsDir() } panic(fmt.Sprintf("Bad field type %T", field.Interface())) } // IsE164 is the validation function for validating if the current field's value is a valid e.164 formatted phone number. func isE164(fl FieldLevel) bool { return e164Regex.MatchString(fl.Field().String()) } // IsEmail is the validation function for validating if the current field's value is a valid email address. func isEmail(fl FieldLevel) bool { return emailRegex.MatchString(fl.Field().String()) } // IsHSLA is the validation function for validating if the current field's value is a valid HSLA color. func isHSLA(fl FieldLevel) bool { return hslaRegex.MatchString(fl.Field().String()) } // IsHSL is the validation function for validating if the current field's value is a valid HSL color. func isHSL(fl FieldLevel) bool { return hslRegex.MatchString(fl.Field().String()) } // IsRGBA is the validation function for validating if the current field's value is a valid RGBA color. func isRGBA(fl FieldLevel) bool { return rgbaRegex.MatchString(fl.Field().String()) } // IsRGB is the validation function for validating if the current field's value is a valid RGB color. func isRGB(fl FieldLevel) bool { return rgbRegex.MatchString(fl.Field().String()) } // IsHEXColor is the validation function for validating if the current field's value is a valid HEX color. func isHEXColor(fl FieldLevel) bool { return hexcolorRegex.MatchString(fl.Field().String()) } // IsHexadecimal is the validation function for validating if the current field's value is a valid hexadecimal. func isHexadecimal(fl FieldLevel) bool { return hexadecimalRegex.MatchString(fl.Field().String()) } // IsNumber is the validation function for validating if the current field's value is a valid number. func isNumber(fl FieldLevel) bool { switch fl.Field().Kind() { case 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: return true default: return numberRegex.MatchString(fl.Field().String()) } } // IsNumeric is the validation function for validating if the current field's value is a valid numeric value. func isNumeric(fl FieldLevel) bool { switch fl.Field().Kind() { case 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: return true default: return numericRegex.MatchString(fl.Field().String()) } } // IsAlphanum is the validation function for validating if the current field's value is a valid alphanumeric value. func isAlphanum(fl FieldLevel) bool { return alphaNumericRegex.MatchString(fl.Field().String()) } // IsAlpha is the validation function for validating if the current field's value is a valid alpha value. func isAlpha(fl FieldLevel) bool { return alphaRegex.MatchString(fl.Field().String()) } // IsAlphanumUnicode is the validation function for validating if the current field's value is a valid alphanumeric unicode value. func isAlphanumUnicode(fl FieldLevel) bool { return alphaUnicodeNumericRegex.MatchString(fl.Field().String()) } // IsAlphaUnicode is the validation function for validating if the current field's value is a valid alpha unicode value. func isAlphaUnicode(fl FieldLevel) bool { return alphaUnicodeRegex.MatchString(fl.Field().String()) } // isDefault is the opposite of required aka hasValue func isDefault(fl FieldLevel) bool { return !hasValue(fl) } // HasValue is the validation function for validating if the current field's value is not the default static value. func hasValue(fl FieldLevel) bool { field := fl.Field() switch field.Kind() { case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func: return !field.IsNil() default: if fl.(*validate).fldIsPointer && field.Interface() != nil { return true } return field.IsValid() && field.Interface() != reflect.Zero(field.Type()).Interface() } } // requireCheckField is a func for check field kind func requireCheckFieldKind(fl FieldLevel, param string, defaultNotFoundValue bool) bool { field := fl.Field() kind := field.Kind() var nullable, found bool if len(param) > 0 { field, kind, nullable, found = fl.GetStructFieldOKAdvanced2(fl.Parent(), param) if !found { return defaultNotFoundValue } } switch kind { case reflect.Invalid: return defaultNotFoundValue case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func: return field.IsNil() default: if nullable && field.Interface() != nil { return false } return field.IsValid() && field.Interface() == reflect.Zero(field.Type()).Interface() } } // requireCheckFieldValue is a func for check field value func requireCheckFieldValue(fl FieldLevel, param string, value string, defaultNotFoundValue bool) bool { field, kind, _, found := fl.GetStructFieldOKAdvanced2(fl.Parent(), param) if !found { return defaultNotFoundValue } switch kind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int() == asInt(value) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return field.Uint() == asUint(value) case reflect.Float32, reflect.Float64: return field.Float() == asFloat(value) case reflect.Slice, reflect.Map, reflect.Array: return int64(field.Len()) == asInt(value) } // default reflect.String: return field.String() == value } // requiredIf is the validation function // The field under validation must be present and not empty only if all the other specified fields are equal to the value following with the specified field. func requiredIf(fl FieldLevel) bool { params := parseOneOfParam2(fl.Param()) if len(params)%2 != 0 { panic(fmt.Sprintf("Bad param number for required_if %s", fl.FieldName())) } for i := 0; i < len(params); i += 2 { if !requireCheckFieldValue(fl, params[i], params[i+1], false) { return true } } return hasValue(fl) } // requiredUnless is the validation function // The field under validation must be present and not empty only unless all the other specified fields are equal to the value following with the specified field. func requiredUnless(fl FieldLevel) bool { params := parseOneOfParam2(fl.Param()) if len(params)%2 != 0 { panic(fmt.Sprintf("Bad param number for required_unless %s", fl.FieldName())) } for i := 0; i < len(params); i += 2 { if requireCheckFieldValue(fl, params[i], params[i+1], false) { return true } } return hasValue(fl) } // ExcludedWith is the validation function // The field under validation must not be present or is empty if any of the other specified fields are present. func excludedWith(fl FieldLevel) bool { params := parseOneOfParam2(fl.Param()) for _, param := range params { if !requireCheckFieldKind(fl, param, true) { return !hasValue(fl) } } return true } // RequiredWith is the validation function // The field under validation must be present and not empty only if any of the other specified fields are present. func requiredWith(fl FieldLevel) bool { params := parseOneOfParam2(fl.Param()) for _, param := range params { if !requireCheckFieldKind(fl, param, true) { return hasValue(fl) } } return true } // ExcludedWithAll is the validation function // The field under validation must not be present or is empty if all of the other specified fields are present. func excludedWithAll(fl FieldLevel) bool { params := parseOneOfParam2(fl.Param()) for _, param := range params { if requireCheckFieldKind(fl, param, true) { return true } } return !hasValue(fl) } // RequiredWithAll is the validation function // The field under validation must be present and not empty only if all of the other specified fields are present. func requiredWithAll(fl FieldLevel) bool { params := parseOneOfParam2(fl.Param()) for _, param := range params { if requireCheckFieldKind(fl, param, true) { return true } } return hasValue(fl) } // ExcludedWithout is the validation function // The field under validation must not be present or is empty when any of the other specified fields are not present. func excludedWithout(fl FieldLevel) bool { if requireCheckFieldKind(fl, strings.TrimSpace(fl.Param()), true) { return !hasValue(fl) } return true } // RequiredWithout is the validation function // The field under validation must be present and not empty only when any of the other specified fields are not present. func requiredWithout(fl FieldLevel) bool { if requireCheckFieldKind(fl, strings.TrimSpace(fl.Param()), true) { return hasValue(fl) } return true } // RequiredWithoutAll is the validation function // The field under validation must not be present or is empty when all of the other specified fields are not present. func excludedWithoutAll(fl FieldLevel) bool { params := parseOneOfParam2(fl.Param()) for _, param := range params { if !requireCheckFieldKind(fl, param, true) { return true } } return !hasValue(fl) } // RequiredWithoutAll is the validation function // The field under validation must be present and not empty only when all of the other specified fields are not present. func requiredWithoutAll(fl FieldLevel) bool { params := parseOneOfParam2(fl.Param()) for _, param := range params { if !requireCheckFieldKind(fl, param, true) { return true } } return hasValue(fl) } // IsGteField is the validation function for validating if the current field's value is greater than or equal to the field specified by the param's value. func isGteField(fl FieldLevel) bool { field := fl.Field() kind := field.Kind() currentField, currentKind, ok := fl.GetStructFieldOK() if !ok || currentKind != kind { return false } switch kind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int() >= currentField.Int() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return field.Uint() >= currentField.Uint() case reflect.Float32, reflect.Float64: return field.Float() >= currentField.Float() case reflect.Struct: fieldType := field.Type() // Not Same underlying type i.e. struct and time if fieldType != currentField.Type() { return false } if fieldType == timeType { t := currentField.Interface().(time.Time) fieldTime := field.Interface().(time.Time) return fieldTime.After(t) || fieldTime.Equal(t) } } // default reflect.String return len(field.String()) >= len(currentField.String()) } // IsGtField is the validation function for validating if the current field's value is greater than the field specified by the param's value. func isGtField(fl FieldLevel) bool { field := fl.Field() kind := field.Kind() currentField, currentKind, ok := fl.GetStructFieldOK() if !ok || currentKind != kind { return false } switch kind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int() > currentField.Int() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return field.Uint() > currentField.Uint() case reflect.Float32, reflect.Float64: return field.Float() > currentField.Float() case reflect.Struct: fieldType := field.Type() // Not Same underlying type i.e. struct and time if fieldType != currentField.Type() { return false } if fieldType == timeType { t := currentField.Interface().(time.Time) fieldTime := field.Interface().(time.Time) return fieldTime.After(t) } } // default reflect.String return len(field.String()) > len(currentField.String()) } // IsGte is the validation function for validating if the current field's value is greater than or equal to the param's value. func isGte(fl FieldLevel) bool { field := fl.Field() param := fl.Param() switch field.Kind() { case reflect.String: p := asInt(param) return int64(utf8.RuneCountInString(field.String())) >= p case reflect.Slice, reflect.Map, reflect.Array: p := asInt(param) return int64(field.Len()) >= p case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: p := asIntFromType(field.Type(), param) return field.Int() >= p case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: p := asUint(param) return field.Uint() >= p case reflect.Float32, reflect.Float64: p := asFloat(param) return field.Float() >= p case reflect.Struct: if field.Type() == timeType { now := time.Now().UTC() t := field.Interface().(time.Time) return t.After(now) || t.Equal(now) } } panic(fmt.Sprintf("Bad field type %T", field.Interface())) } // IsGt is the validation function for validating if the current field's value is greater than the param's value. func isGt(fl FieldLevel) bool { field := fl.Field() param := fl.Param() switch field.Kind() { case reflect.String: p := asInt(param) return int64(utf8.RuneCountInString(field.String())) > p case reflect.Slice, reflect.Map, reflect.Array: p := asInt(param) return int64(field.Len()) > p case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: p := asIntFromType(field.Type(), param) return field.Int() > p case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: p := asUint(param) return field.Uint() > p case reflect.Float32, reflect.Float64: p := asFloat(param) return field.Float() > p case reflect.Struct: if field.Type() == timeType { return field.Interface().(time.Time).After(time.Now().UTC()) } } panic(fmt.Sprintf("Bad field type %T", field.Interface())) } // HasLengthOf is the validation function for validating if the current field's value is equal to the param's value. func hasLengthOf(fl FieldLevel) bool { field := fl.Field() param := fl.Param() switch field.Kind() { case reflect.String: p := asInt(param) return int64(utf8.RuneCountInString(field.String())) == p case reflect.Slice, reflect.Map, reflect.Array: p := asInt(param) return int64(field.Len()) == p case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: p := asIntFromType(field.Type(), param) return field.Int() == p case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: p := asUint(param) return field.Uint() == p case reflect.Float32, reflect.Float64: p := asFloat(param) return field.Float() == p } panic(fmt.Sprintf("Bad field type %T", field.Interface())) } // HasMinOf is the validation function for validating if the current field's value is greater than or equal to the param's value. func hasMinOf(fl FieldLevel) bool { return isGte(fl) } // IsLteField is the validation function for validating if the current field's value is less than or equal to the field specified by the param's value. func isLteField(fl FieldLevel) bool { field := fl.Field() kind := field.Kind() currentField, currentKind, ok := fl.GetStructFieldOK() if !ok || currentKind != kind { return false } switch kind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int() <= currentField.Int() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return field.Uint() <= currentField.Uint() case reflect.Float32, reflect.Float64: return field.Float() <= currentField.Float() case reflect.Struct: fieldType := field.Type() // Not Same underlying type i.e. struct and time if fieldType != currentField.Type() { return false } if fieldType == timeType { t := currentField.Interface().(time.Time) fieldTime := field.Interface().(time.Time) return fieldTime.Before(t) || fieldTime.Equal(t) } } // default reflect.String return len(field.String()) <= len(currentField.String()) } // IsLtField is the validation function for validating if the current field's value is less than the field specified by the param's value. func isLtField(fl FieldLevel) bool { field := fl.Field() kind := field.Kind() currentField, currentKind, ok := fl.GetStructFieldOK() if !ok || currentKind != kind { return false } switch kind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int() < currentField.Int() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return field.Uint() < currentField.Uint() case reflect.Float32, reflect.Float64: return field.Float() < currentField.Float() case reflect.Struct: fieldType := field.Type() // Not Same underlying type i.e. struct and time if fieldType != currentField.Type() { return false } if fieldType == timeType { t := currentField.Interface().(time.Time) fieldTime := field.Interface().(time.Time) return fieldTime.Before(t) } } // default reflect.String return len(field.String()) < len(currentField.String()) } // IsLte is the validation function for validating if the current field's value is less than or equal to the param's value. func isLte(fl FieldLevel) bool { field := fl.Field() param := fl.Param() switch field.Kind() { case reflect.String: p := asInt(param) return int64(utf8.RuneCountInString(field.String())) <= p case reflect.Slice, reflect.Map, reflect.Array: p := asInt(param) return int64(field.Len()) <= p case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: p := asIntFromType(field.Type(), param) return field.Int() <= p case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: p := asUint(param) return field.Uint() <= p case reflect.Float32, reflect.Float64: p := asFloat(param) return field.Float() <= p case reflect.Struct: if field.Type() == timeType { now := time.Now().UTC() t := field.Interface().(time.Time) return t.Before(now) || t.Equal(now) } } panic(fmt.Sprintf("Bad field type %T", field.Interface())) } // IsLt is the validation function for validating if the current field's value is less than the param's value. func isLt(fl FieldLevel) bool { field := fl.Field() param := fl.Param() switch field.Kind() { case reflect.String: p := asInt(param) return int64(utf8.RuneCountInString(field.String())) < p case reflect.Slice, reflect.Map, reflect.Array: p := asInt(param) return int64(field.Len()) < p case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: p := asIntFromType(field.Type(), param) return field.Int() < p case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: p := asUint(param) return field.Uint() < p case reflect.Float32, reflect.Float64: p := asFloat(param) return field.Float() < p case reflect.Struct: if field.Type() == timeType { return field.Interface().(time.Time).Before(time.Now().UTC()) } } panic(fmt.Sprintf("Bad field type %T", field.Interface())) } // HasMaxOf is the validation function for validating if the current field's value is less than or equal to the param's value. func hasMaxOf(fl FieldLevel) bool { return isLte(fl) } // IsTCP4AddrResolvable is the validation function for validating if the field's value is a resolvable tcp4 address. func isTCP4AddrResolvable(fl FieldLevel) bool { if !isIP4Addr(fl) { return false } _, err := net.ResolveTCPAddr("tcp4", fl.Field().String()) return err == nil } // IsTCP6AddrResolvable is the validation function for validating if the field's value is a resolvable tcp6 address. func isTCP6AddrResolvable(fl FieldLevel) bool { if !isIP6Addr(fl) { return false } _, err := net.ResolveTCPAddr("tcp6", fl.Field().String()) return err == nil } // IsTCPAddrResolvable is the validation function for validating if the field's value is a resolvable tcp address. func isTCPAddrResolvable(fl FieldLevel) bool { if !isIP4Addr(fl) && !isIP6Addr(fl) { return false } _, err := net.ResolveTCPAddr("tcp", fl.Field().String()) return err == nil } // IsUDP4AddrResolvable is the validation function for validating if the field's value is a resolvable udp4 address. func isUDP4AddrResolvable(fl FieldLevel) bool { if !isIP4Addr(fl) { return false } _, err := net.ResolveUDPAddr("udp4", fl.Field().String()) return err == nil } // IsUDP6AddrResolvable is the validation function for validating if the field's value is a resolvable udp6 address. func isUDP6AddrResolvable(fl FieldLevel) bool { if !isIP6Addr(fl) { return false } _, err := net.ResolveUDPAddr("udp6", fl.Field().String()) return err == nil } // IsUDPAddrResolvable is the validation function for validating if the field's value is a resolvable udp address. func isUDPAddrResolvable(fl FieldLevel) bool { if !isIP4Addr(fl) && !isIP6Addr(fl) { return false } _, err := net.ResolveUDPAddr("udp", fl.Field().String()) return err == nil } // IsIP4AddrResolvable is the validation function for validating if the field's value is a resolvable ip4 address. func isIP4AddrResolvable(fl FieldLevel) bool { if !isIPv4(fl) { return false } _, err := net.ResolveIPAddr("ip4", fl.Field().String()) return err == nil } // IsIP6AddrResolvable is the validation function for validating if the field's value is a resolvable ip6 address. func isIP6AddrResolvable(fl FieldLevel) bool { if !isIPv6(fl) { return false } _, err := net.ResolveIPAddr("ip6", fl.Field().String()) return err == nil } // IsIPAddrResolvable is the validation function for validating if the field's value is a resolvable ip address. func isIPAddrResolvable(fl FieldLevel) bool { if !isIP(fl) { return false } _, err := net.ResolveIPAddr("ip", fl.Field().String()) return err == nil } // IsUnixAddrResolvable is the validation function for validating if the field's value is a resolvable unix address. func isUnixAddrResolvable(fl FieldLevel) bool { _, err := net.ResolveUnixAddr("unix", fl.Field().String()) return err == nil } func isIP4Addr(fl FieldLevel) bool { val := fl.Field().String() if idx := strings.LastIndex(val, ":"); idx != -1 { val = val[0:idx] } ip := net.ParseIP(val) return ip != nil && ip.To4() != nil } func isIP6Addr(fl FieldLevel) bool { val := fl.Field().String() if idx := strings.LastIndex(val, ":"); idx != -1 { if idx != 0 && val[idx-1:idx] == "]" { val = val[1 : idx-1] } } ip := net.ParseIP(val) return ip != nil && ip.To4() == nil } func isHostnameRFC952(fl FieldLevel) bool { return hostnameRegexRFC952.MatchString(fl.Field().String()) } func isHostnameRFC1123(fl FieldLevel) bool { return hostnameRegexRFC1123.MatchString(fl.Field().String()) } func isFQDN(fl FieldLevel) bool { val := fl.Field().String() if val == "" { return false } return fqdnRegexRFC1123.MatchString(val) } // IsDir is the validation function for validating if the current field's value is a valid directory. func isDir(fl FieldLevel) bool { field := fl.Field() if field.Kind() == reflect.String { fileInfo, err := os.Stat(field.String()) if err != nil { return false } return fileInfo.IsDir() } panic(fmt.Sprintf("Bad field type %T", field.Interface())) } // isJSON is the validation function for validating if the current field's value is a valid json string. func isJSON(fl FieldLevel) bool { field := fl.Field() if field.Kind() == reflect.String { val := field.String() return json.Valid([]byte(val)) } panic(fmt.Sprintf("Bad field type %T", field.Interface())) } // isHostnamePort validates a : combination for fields typically used for socket address. func isHostnamePort(fl FieldLevel) bool { val := fl.Field().String() host, port, err := net.SplitHostPort(val) if err != nil { return false } // Port must be a iny <= 65535. if portNum, err := strconv.ParseInt(port, 10, 32); err != nil || portNum > 65535 || portNum < 1 { return false } // If host is specified, it should match a DNS name if host != "" { return hostnameRegexRFC1123.MatchString(host) } return true } // isLowercase is the validation function for validating if the current field's value is a lowercase string. func isLowercase(fl FieldLevel) bool { field := fl.Field() if field.Kind() == reflect.String { if field.String() == "" { return false } return field.String() == strings.ToLower(field.String()) } panic(fmt.Sprintf("Bad field type %T", field.Interface())) } // isUppercase is the validation function for validating if the current field's value is an uppercase string. func isUppercase(fl FieldLevel) bool { field := fl.Field() if field.Kind() == reflect.String { if field.String() == "" { return false } return field.String() == strings.ToUpper(field.String()) } panic(fmt.Sprintf("Bad field type %T", field.Interface())) } // isDatetime is the validation function for validating if the current field's value is a valid datetime string. func isDatetime(fl FieldLevel) bool { field := fl.Field() param := fl.Param() if field.Kind() == reflect.String { _, err := time.Parse(param, field.String()) return err == nil } panic(fmt.Sprintf("Bad field type %T", field.Interface())) } // isTimeZone is the validation function for validating if the current field's value is a valid time zone string. func isTimeZone(fl FieldLevel) bool { field := fl.Field() if field.Kind() == reflect.String { // empty value is converted to UTC by time.LoadLocation but disallow it as it is not a valid time zone name if field.String() == "" { return false } // Local value is converted to the current system time zone by time.LoadLocation but disallow it as it is not a valid time zone name if strings.ToLower(field.String()) == "local" { return false } _, err := time.LoadLocation(field.String()) return err == nil } panic(fmt.Sprintf("Bad field type %T", field.Interface())) } // isIso3166Alpha2 is the validation function for validating if the current field's value is a valid iso3166-1 alpha-2 country code. func isIso3166Alpha2(fl FieldLevel) bool { val := fl.Field().String() return iso3166_1_alpha2[val] } // isIso3166Alpha2 is the validation function for validating if the current field's value is a valid iso3166-1 alpha-3 country code. func isIso3166Alpha3(fl FieldLevel) bool { val := fl.Field().String() return iso3166_1_alpha3[val] } // isIso3166Alpha2 is the validation function for validating if the current field's value is a valid iso3166-1 alpha-numeric country code. func isIso3166AlphaNumeric(fl FieldLevel) bool { field := fl.Field() var code int switch field.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: code = int(field.Int() % 1000) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: code = int(field.Uint() % 1000) default: panic(fmt.Sprintf("Bad field type %T", field.Interface())) } return iso3166_1_alpha_numeric[code] } validator-10.4.1/benchmarks_test.go000066400000000000000000000502241374261122600172740ustar00rootroot00000000000000package validator import ( "bytes" sql "database/sql/driver" "testing" "time" ) func BenchmarkFieldSuccess(b *testing.B) { validate := New() s := "1" b.ResetTimer() for n := 0; n < b.N; n++ { _ = validate.Var(&s, "len=1") } } func BenchmarkFieldSuccessParallel(b *testing.B) { validate := New() s := "1" b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = validate.Var(&s, "len=1") } }) } func BenchmarkFieldFailure(b *testing.B) { validate := New() s := "12" b.ResetTimer() for n := 0; n < b.N; n++ { _ = validate.Var(&s, "len=1") } } func BenchmarkFieldFailureParallel(b *testing.B) { validate := New() s := "12" b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = validate.Var(&s, "len=1") } }) } func BenchmarkFieldArrayDiveSuccess(b *testing.B) { validate := New() m := []string{"val1", "val2", "val3"} b.ResetTimer() for n := 0; n < b.N; n++ { _ = validate.Var(m, "required,dive,required") } } func BenchmarkFieldArrayDiveSuccessParallel(b *testing.B) { validate := New() m := []string{"val1", "val2", "val3"} b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = validate.Var(m, "required,dive,required") } }) } func BenchmarkFieldArrayDiveFailure(b *testing.B) { validate := New() m := []string{"val1", "", "val3"} b.ResetTimer() for n := 0; n < b.N; n++ { _ = validate.Var(m, "required,dive,required") } } func BenchmarkFieldArrayDiveFailureParallel(b *testing.B) { validate := New() m := []string{"val1", "", "val3"} b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = validate.Var(m, "required,dive,required") } }) } func BenchmarkFieldMapDiveSuccess(b *testing.B) { validate := New() m := map[string]string{"val1": "val1", "val2": "val2", "val3": "val3"} b.ResetTimer() for n := 0; n < b.N; n++ { _ = validate.Var(m, "required,dive,required") } } func BenchmarkFieldMapDiveSuccessParallel(b *testing.B) { validate := New() m := map[string]string{"val1": "val1", "val2": "val2", "val3": "val3"} b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = validate.Var(m, "required,dive,required") } }) } func BenchmarkFieldMapDiveFailure(b *testing.B) { validate := New() m := map[string]string{"": "", "val3": "val3"} b.ResetTimer() for n := 0; n < b.N; n++ { _ = validate.Var(m, "required,dive,required") } } func BenchmarkFieldMapDiveFailureParallel(b *testing.B) { validate := New() m := map[string]string{"": "", "val3": "val3"} b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = validate.Var(m, "required,dive,required") } }) } func BenchmarkFieldMapDiveWithKeysSuccess(b *testing.B) { validate := New() m := map[string]string{"val1": "val1", "val2": "val2", "val3": "val3"} b.ResetTimer() for n := 0; n < b.N; n++ { _ = validate.Var(m, "required,dive,keys,required,endkeys,required") } } func BenchmarkFieldMapDiveWithKeysSuccessParallel(b *testing.B) { validate := New() m := map[string]string{"val1": "val1", "val2": "val2", "val3": "val3"} b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = validate.Var(m, "required,dive,keys,required,endkeys,required") } }) } func BenchmarkFieldMapDiveWithKeysFailure(b *testing.B) { validate := New() m := map[string]string{"": "", "val3": "val3"} b.ResetTimer() for n := 0; n < b.N; n++ { _ = validate.Var(m, "required,dive,keys,required,endkeys,required") } } func BenchmarkFieldMapDiveWithKeysFailureParallel(b *testing.B) { validate := New() m := map[string]string{"": "", "val3": "val3"} b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = validate.Var(m, "required,dive,keys,required,endkeys,required") } }) } func BenchmarkFieldCustomTypeSuccess(b *testing.B) { validate := New() validate.RegisterCustomTypeFunc(ValidateValuerType, (*sql.Valuer)(nil), valuer{}) val := valuer{ Name: "1", } b.ResetTimer() for n := 0; n < b.N; n++ { _ = validate.Var(val, "len=1") } } func BenchmarkFieldCustomTypeSuccessParallel(b *testing.B) { validate := New() validate.RegisterCustomTypeFunc(ValidateValuerType, (*sql.Valuer)(nil), valuer{}) val := valuer{ Name: "1", } b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = validate.Var(val, "len=1") } }) } func BenchmarkFieldCustomTypeFailure(b *testing.B) { validate := New() validate.RegisterCustomTypeFunc(ValidateValuerType, (*sql.Valuer)(nil), valuer{}) val := valuer{} b.ResetTimer() for n := 0; n < b.N; n++ { _ = validate.Var(val, "len=1") } } func BenchmarkFieldCustomTypeFailureParallel(b *testing.B) { validate := New() validate.RegisterCustomTypeFunc(ValidateValuerType, (*sql.Valuer)(nil), valuer{}) val := valuer{} b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = validate.Var(val, "len=1") } }) } func BenchmarkFieldOrTagSuccess(b *testing.B) { validate := New() s := "rgba(0,0,0,1)" b.ResetTimer() for n := 0; n < b.N; n++ { _ = validate.Var(s, "rgb|rgba") } } func BenchmarkFieldOrTagSuccessParallel(b *testing.B) { validate := New() s := "rgba(0,0,0,1)" b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = validate.Var(s, "rgb|rgba") } }) } func BenchmarkFieldOrTagFailure(b *testing.B) { validate := New() s := "#000" b.ResetTimer() for n := 0; n < b.N; n++ { _ = validate.Var(s, "rgb|rgba") } } func BenchmarkFieldOrTagFailureParallel(b *testing.B) { validate := New() s := "#000" b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = validate.Var(s, "rgb|rgba") } }) } func BenchmarkStructLevelValidationSuccess(b *testing.B) { validate := New() validate.RegisterStructValidation(StructValidationTestStructSuccess, TestStruct{}) tst := TestStruct{ String: "good value", } b.ResetTimer() for n := 0; n < b.N; n++ { _ = validate.Struct(tst) } } func BenchmarkStructLevelValidationSuccessParallel(b *testing.B) { validate := New() validate.RegisterStructValidation(StructValidationTestStructSuccess, TestStruct{}) tst := TestStruct{ String: "good value", } b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = validate.Struct(tst) } }) } func BenchmarkStructLevelValidationFailure(b *testing.B) { validate := New() validate.RegisterStructValidation(StructValidationTestStruct, TestStruct{}) tst := TestStruct{ String: "good value", } b.ResetTimer() for n := 0; n < b.N; n++ { _ = validate.Struct(tst) } } func BenchmarkStructLevelValidationFailureParallel(b *testing.B) { validate := New() validate.RegisterStructValidation(StructValidationTestStruct, TestStruct{}) tst := TestStruct{ String: "good value", } b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = validate.Struct(tst) } }) } func BenchmarkStructSimpleCustomTypeSuccess(b *testing.B) { validate := New() validate.RegisterCustomTypeFunc(ValidateValuerType, (*sql.Valuer)(nil), valuer{}) val := valuer{ Name: "1", } type Foo struct { Valuer valuer `validate:"len=1"` IntValue int `validate:"min=5,max=10"` } validFoo := &Foo{Valuer: val, IntValue: 7} b.ResetTimer() for n := 0; n < b.N; n++ { _ = validate.Struct(validFoo) } } func BenchmarkStructSimpleCustomTypeSuccessParallel(b *testing.B) { validate := New() validate.RegisterCustomTypeFunc(ValidateValuerType, (*sql.Valuer)(nil), valuer{}) val := valuer{ Name: "1", } type Foo struct { Valuer valuer `validate:"len=1"` IntValue int `validate:"min=5,max=10"` } validFoo := &Foo{Valuer: val, IntValue: 7} b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = validate.Struct(validFoo) } }) } func BenchmarkStructSimpleCustomTypeFailure(b *testing.B) { validate := New() validate.RegisterCustomTypeFunc(ValidateValuerType, (*sql.Valuer)(nil), valuer{}) val := valuer{} type Foo struct { Valuer valuer `validate:"len=1"` IntValue int `validate:"min=5,max=10"` } validFoo := &Foo{Valuer: val, IntValue: 3} b.ResetTimer() for n := 0; n < b.N; n++ { _ = validate.Struct(validFoo) } } func BenchmarkStructSimpleCustomTypeFailureParallel(b *testing.B) { validate := New() validate.RegisterCustomTypeFunc(ValidateValuerType, (*sql.Valuer)(nil), valuer{}) val := valuer{} type Foo struct { Valuer valuer `validate:"len=1"` IntValue int `validate:"min=5,max=10"` } validFoo := &Foo{Valuer: val, IntValue: 3} b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = validate.Struct(validate.Struct(validFoo)) } }) } func BenchmarkStructFilteredSuccess(b *testing.B) { validate := New() type Test struct { Name string `validate:"required"` NickName string `validate:"required"` } test := &Test{ Name: "Joey Bloggs", } byts := []byte("Name") fn := func(ns []byte) bool { return !bytes.HasSuffix(ns, byts) } b.ResetTimer() for n := 0; n < b.N; n++ { _ = validate.StructFiltered(test, fn) } } func BenchmarkStructFilteredSuccessParallel(b *testing.B) { validate := New() type Test struct { Name string `validate:"required"` NickName string `validate:"required"` } test := &Test{ Name: "Joey Bloggs", } byts := []byte("Name") fn := func(ns []byte) bool { return !bytes.HasSuffix(ns, byts) } b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = validate.StructFiltered(test, fn) } }) } func BenchmarkStructFilteredFailure(b *testing.B) { validate := New() type Test struct { Name string `validate:"required"` NickName string `validate:"required"` } test := &Test{ Name: "Joey Bloggs", } byts := []byte("NickName") fn := func(ns []byte) bool { return !bytes.HasSuffix(ns, byts) } b.ResetTimer() for n := 0; n < b.N; n++ { _ = validate.StructFiltered(test, fn) } } func BenchmarkStructFilteredFailureParallel(b *testing.B) { validate := New() type Test struct { Name string `validate:"required"` NickName string `validate:"required"` } test := &Test{ Name: "Joey Bloggs", } byts := []byte("NickName") fn := func(ns []byte) bool { return !bytes.HasSuffix(ns, byts) } b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = validate.StructFiltered(test, fn) } }) } func BenchmarkStructPartialSuccess(b *testing.B) { validate := New() type Test struct { Name string `validate:"required"` NickName string `validate:"required"` } test := &Test{ Name: "Joey Bloggs", } b.ResetTimer() for n := 0; n < b.N; n++ { _ = validate.StructPartial(test, "Name") } } func BenchmarkStructPartialSuccessParallel(b *testing.B) { validate := New() type Test struct { Name string `validate:"required"` NickName string `validate:"required"` } test := &Test{ Name: "Joey Bloggs", } b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = validate.StructPartial(test, "Name") } }) } func BenchmarkStructPartialFailure(b *testing.B) { validate := New() type Test struct { Name string `validate:"required"` NickName string `validate:"required"` } test := &Test{ Name: "Joey Bloggs", } b.ResetTimer() for n := 0; n < b.N; n++ { _ = validate.StructPartial(test, "NickName") } } func BenchmarkStructPartialFailureParallel(b *testing.B) { validate := New() type Test struct { Name string `validate:"required"` NickName string `validate:"required"` } test := &Test{ Name: "Joey Bloggs", } b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = validate.StructPartial(test, "NickName") } }) } func BenchmarkStructExceptSuccess(b *testing.B) { validate := New() type Test struct { Name string `validate:"required"` NickName string `validate:"required"` } test := &Test{ Name: "Joey Bloggs", } b.ResetTimer() for n := 0; n < b.N; n++ { _ = validate.StructExcept(test, "Nickname") } } func BenchmarkStructExceptSuccessParallel(b *testing.B) { validate := New() type Test struct { Name string `validate:"required"` NickName string `validate:"required"` } test := &Test{ Name: "Joey Bloggs", } b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = validate.StructExcept(test, "NickName") } }) } func BenchmarkStructExceptFailure(b *testing.B) { validate := New() type Test struct { Name string `validate:"required"` NickName string `validate:"required"` } test := &Test{ Name: "Joey Bloggs", } b.ResetTimer() for n := 0; n < b.N; n++ { _ = validate.StructExcept(test, "Name") } } func BenchmarkStructExceptFailureParallel(b *testing.B) { validate := New() type Test struct { Name string `validate:"required"` NickName string `validate:"required"` } test := &Test{ Name: "Joey Bloggs", } b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = validate.StructExcept(test, "Name") } }) } func BenchmarkStructSimpleCrossFieldSuccess(b *testing.B) { validate := New() type Test struct { Start time.Time End time.Time `validate:"gtfield=Start"` } now := time.Now().UTC() then := now.Add(time.Hour * 5) test := &Test{ Start: now, End: then, } b.ResetTimer() for n := 0; n < b.N; n++ { _ = validate.Struct(test) } } func BenchmarkStructSimpleCrossFieldSuccessParallel(b *testing.B) { validate := New() type Test struct { Start time.Time End time.Time `validate:"gtfield=Start"` } now := time.Now().UTC() then := now.Add(time.Hour * 5) test := &Test{ Start: now, End: then, } b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = validate.Struct(test) } }) } func BenchmarkStructSimpleCrossFieldFailure(b *testing.B) { validate := New() type Test struct { Start time.Time End time.Time `validate:"gtfield=Start"` } now := time.Now().UTC() then := now.Add(time.Hour * -5) test := &Test{ Start: now, End: then, } b.ResetTimer() for n := 0; n < b.N; n++ { _ = validate.Struct(test) } } func BenchmarkStructSimpleCrossFieldFailureParallel(b *testing.B) { validate := New() type Test struct { Start time.Time End time.Time `validate:"gtfield=Start"` } now := time.Now().UTC() then := now.Add(time.Hour * -5) test := &Test{ Start: now, End: then, } b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = validate.Struct(test) } }) } func BenchmarkStructSimpleCrossStructCrossFieldSuccess(b *testing.B) { validate := New() type Inner struct { Start time.Time } type Outer struct { Inner *Inner CreatedAt time.Time `validate:"eqcsfield=Inner.Start"` } now := time.Now().UTC() inner := &Inner{ Start: now, } outer := &Outer{ Inner: inner, CreatedAt: now, } b.ResetTimer() for n := 0; n < b.N; n++ { _ = validate.Struct(outer) } } func BenchmarkStructSimpleCrossStructCrossFieldSuccessParallel(b *testing.B) { validate := New() type Inner struct { Start time.Time } type Outer struct { Inner *Inner CreatedAt time.Time `validate:"eqcsfield=Inner.Start"` } now := time.Now().UTC() inner := &Inner{ Start: now, } outer := &Outer{ Inner: inner, CreatedAt: now, } b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = validate.Struct(outer) } }) } func BenchmarkStructSimpleCrossStructCrossFieldFailure(b *testing.B) { validate := New() type Inner struct { Start time.Time } type Outer struct { Inner *Inner CreatedAt time.Time `validate:"eqcsfield=Inner.Start"` } now := time.Now().UTC() then := now.Add(time.Hour * 5) inner := &Inner{ Start: then, } outer := &Outer{ Inner: inner, CreatedAt: now, } b.ResetTimer() for n := 0; n < b.N; n++ { _ = validate.Struct(outer) } } func BenchmarkStructSimpleCrossStructCrossFieldFailureParallel(b *testing.B) { validate := New() type Inner struct { Start time.Time } type Outer struct { Inner *Inner CreatedAt time.Time `validate:"eqcsfield=Inner.Start"` } now := time.Now().UTC() then := now.Add(time.Hour * 5) inner := &Inner{ Start: then, } outer := &Outer{ Inner: inner, CreatedAt: now, } b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = validate.Struct(outer) } }) } func BenchmarkStructSimpleSuccess(b *testing.B) { validate := New() type Foo struct { StringValue string `validate:"min=5,max=10"` IntValue int `validate:"min=5,max=10"` } validFoo := &Foo{StringValue: "Foobar", IntValue: 7} b.ResetTimer() for n := 0; n < b.N; n++ { _ = validate.Struct(validFoo) } } func BenchmarkStructSimpleSuccessParallel(b *testing.B) { validate := New() type Foo struct { StringValue string `validate:"min=5,max=10"` IntValue int `validate:"min=5,max=10"` } validFoo := &Foo{StringValue: "Foobar", IntValue: 7} b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = validate.Struct(validFoo) } }) } func BenchmarkStructSimpleFailure(b *testing.B) { validate := New() type Foo struct { StringValue string `validate:"min=5,max=10"` IntValue int `validate:"min=5,max=10"` } invalidFoo := &Foo{StringValue: "Fo", IntValue: 3} b.ResetTimer() for n := 0; n < b.N; n++ { _ = validate.Struct(invalidFoo) } } func BenchmarkStructSimpleFailureParallel(b *testing.B) { validate := New() type Foo struct { StringValue string `validate:"min=5,max=10"` IntValue int `validate:"min=5,max=10"` } invalidFoo := &Foo{StringValue: "Fo", IntValue: 3} b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = validate.Struct(invalidFoo) } }) } func BenchmarkStructComplexSuccess(b *testing.B) { validate := New() tSuccess := &TestString{ Required: "Required", Len: "length==10", Min: "min=1", Max: "1234567890", MinMax: "12345", Lt: "012345678", Lte: "0123456789", Gt: "01234567890", Gte: "0123456789", OmitEmpty: "", Sub: &SubTest{ Test: "1", }, SubIgnore: &SubTest{ Test: "", }, Anonymous: struct { A string `validate:"required"` }{ A: "1", }, Iface: &Impl{ F: "123", }, } b.ResetTimer() for n := 0; n < b.N; n++ { _ = validate.Struct(tSuccess) } } func BenchmarkStructComplexSuccessParallel(b *testing.B) { validate := New() tSuccess := &TestString{ Required: "Required", Len: "length==10", Min: "min=1", Max: "1234567890", MinMax: "12345", Lt: "012345678", Lte: "0123456789", Gt: "01234567890", Gte: "0123456789", OmitEmpty: "", Sub: &SubTest{ Test: "1", }, SubIgnore: &SubTest{ Test: "", }, Anonymous: struct { A string `validate:"required"` }{ A: "1", }, Iface: &Impl{ F: "123", }, } b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = validate.Struct(tSuccess) } }) } func BenchmarkStructComplexFailure(b *testing.B) { validate := New() tFail := &TestString{ Required: "", Len: "", Min: "", Max: "12345678901", MinMax: "", Lt: "0123456789", Lte: "01234567890", Gt: "1", Gte: "1", OmitEmpty: "12345678901", Sub: &SubTest{ Test: "", }, Anonymous: struct { A string `validate:"required"` }{ A: "", }, Iface: &Impl{ F: "12", }, } b.ResetTimer() for n := 0; n < b.N; n++ { _ = validate.Struct(tFail) } } func BenchmarkStructComplexFailureParallel(b *testing.B) { validate := New() tFail := &TestString{ Required: "", Len: "", Min: "", Max: "12345678901", MinMax: "", Lt: "0123456789", Lte: "01234567890", Gt: "1", Gte: "1", OmitEmpty: "12345678901", Sub: &SubTest{ Test: "", }, Anonymous: struct { A string `validate:"required"` }{ A: "", }, Iface: &Impl{ F: "12", }, } b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = validate.Struct(tFail) } }) } type TestOneof struct { Color string `validate:"oneof=red green"` } func BenchmarkOneof(b *testing.B) { w := &TestOneof{Color: "green"} val := New() for i := 0; i < b.N; i++ { _ = val.Struct(w) } } func BenchmarkOneofParallel(b *testing.B) { w := &TestOneof{Color: "green"} val := New() b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = val.Struct(w) } }) } validator-10.4.1/cache.go000066400000000000000000000166601374261122600151710ustar00rootroot00000000000000package validator import ( "fmt" "reflect" "strings" "sync" "sync/atomic" ) type tagType uint8 const ( typeDefault tagType = iota typeOmitEmpty typeIsDefault typeNoStructLevel typeStructOnly typeDive typeOr typeKeys typeEndKeys ) const ( invalidValidation = "Invalid validation tag on field '%s'" undefinedValidation = "Undefined validation function '%s' on field '%s'" keysTagNotDefined = "'" + endKeysTag + "' tag encountered without a corresponding '" + keysTag + "' tag" ) type structCache struct { lock sync.Mutex m atomic.Value // map[reflect.Type]*cStruct } func (sc *structCache) Get(key reflect.Type) (c *cStruct, found bool) { c, found = sc.m.Load().(map[reflect.Type]*cStruct)[key] return } func (sc *structCache) Set(key reflect.Type, value *cStruct) { m := sc.m.Load().(map[reflect.Type]*cStruct) nm := make(map[reflect.Type]*cStruct, len(m)+1) for k, v := range m { nm[k] = v } nm[key] = value sc.m.Store(nm) } type tagCache struct { lock sync.Mutex m atomic.Value // map[string]*cTag } func (tc *tagCache) Get(key string) (c *cTag, found bool) { c, found = tc.m.Load().(map[string]*cTag)[key] return } func (tc *tagCache) Set(key string, value *cTag) { m := tc.m.Load().(map[string]*cTag) nm := make(map[string]*cTag, len(m)+1) for k, v := range m { nm[k] = v } nm[key] = value tc.m.Store(nm) } type cStruct struct { name string fields []*cField fn StructLevelFuncCtx } type cField struct { idx int name string altName string namesEqual bool cTags *cTag } type cTag struct { tag string aliasTag string actualAliasTag string param string keys *cTag // only populated when using tag's 'keys' and 'endkeys' for map key validation next *cTag fn FuncCtx typeof tagType hasTag bool hasAlias bool hasParam bool // true if parameter used eg. eq= where the equal sign has been set isBlockEnd bool // indicates the current tag represents the last validation in the block runValidationWhenNil bool } func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStruct { v.structCache.lock.Lock() defer v.structCache.lock.Unlock() // leave as defer! because if inner panics, it will never get unlocked otherwise! typ := current.Type() // could have been multiple trying to access, but once first is done this ensures struct // isn't parsed again. cs, ok := v.structCache.Get(typ) if ok { return cs } cs = &cStruct{name: sName, fields: make([]*cField, 0), fn: v.structLevelFuncs[typ]} numFields := current.NumField() var ctag *cTag var fld reflect.StructField var tag string var customName string for i := 0; i < numFields; i++ { fld = typ.Field(i) if !fld.Anonymous && len(fld.PkgPath) > 0 { continue } tag = fld.Tag.Get(v.tagName) if tag == skipValidationTag { continue } customName = fld.Name if v.hasTagNameFunc { name := v.tagNameFunc(fld) if len(name) > 0 { customName = name } } // NOTE: cannot use shared tag cache, because tags may be equal, but things like alias may be different // and so only struct level caching can be used instead of combined with Field tag caching if len(tag) > 0 { ctag, _ = v.parseFieldTagsRecursive(tag, fld.Name, "", false) } else { // even if field doesn't have validations need cTag for traversing to potential inner/nested // elements of the field. ctag = new(cTag) } cs.fields = append(cs.fields, &cField{ idx: i, name: fld.Name, altName: customName, cTags: ctag, namesEqual: fld.Name == customName, }) } v.structCache.Set(typ, cs) return cs } func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string, alias string, hasAlias bool) (firstCtag *cTag, current *cTag) { var t string noAlias := len(alias) == 0 tags := strings.Split(tag, tagSeparator) for i := 0; i < len(tags); i++ { t = tags[i] if noAlias { alias = t } // check map for alias and process new tags, otherwise process as usual if tagsVal, found := v.aliases[t]; found { if i == 0 { firstCtag, current = v.parseFieldTagsRecursive(tagsVal, fieldName, t, true) } else { next, curr := v.parseFieldTagsRecursive(tagsVal, fieldName, t, true) current.next, current = next, curr } continue } var prevTag tagType if i == 0 { current = &cTag{aliasTag: alias, hasAlias: hasAlias, hasTag: true, typeof: typeDefault} firstCtag = current } else { prevTag = current.typeof current.next = &cTag{aliasTag: alias, hasAlias: hasAlias, hasTag: true} current = current.next } switch t { case diveTag: current.typeof = typeDive continue case keysTag: current.typeof = typeKeys if i == 0 || prevTag != typeDive { panic(fmt.Sprintf("'%s' tag must be immediately preceded by the '%s' tag", keysTag, diveTag)) } current.typeof = typeKeys // need to pass along only keys tag // need to increment i to skip over the keys tags b := make([]byte, 0, 64) i++ for ; i < len(tags); i++ { b = append(b, tags[i]...) b = append(b, ',') if tags[i] == endKeysTag { break } } current.keys, _ = v.parseFieldTagsRecursive(string(b[:len(b)-1]), fieldName, "", false) continue case endKeysTag: current.typeof = typeEndKeys // if there are more in tags then there was no keysTag defined // and an error should be thrown if i != len(tags)-1 { panic(keysTagNotDefined) } return case omitempty: current.typeof = typeOmitEmpty continue case structOnlyTag: current.typeof = typeStructOnly continue case noStructLevelTag: current.typeof = typeNoStructLevel continue default: if t == isdefault { current.typeof = typeIsDefault } // if a pipe character is needed within the param you must use the utf8Pipe representation "0x7C" orVals := strings.Split(t, orSeparator) for j := 0; j < len(orVals); j++ { vals := strings.SplitN(orVals[j], tagKeySeparator, 2) if noAlias { alias = vals[0] current.aliasTag = alias } else { current.actualAliasTag = t } if j > 0 { current.next = &cTag{aliasTag: alias, actualAliasTag: current.actualAliasTag, hasAlias: hasAlias, hasTag: true} current = current.next } current.hasParam = len(vals) > 1 current.tag = vals[0] if len(current.tag) == 0 { panic(strings.TrimSpace(fmt.Sprintf(invalidValidation, fieldName))) } if wrapper, ok := v.validations[current.tag]; ok { current.fn = wrapper.fn current.runValidationWhenNil = wrapper.runValidatinOnNil } else { panic(strings.TrimSpace(fmt.Sprintf(undefinedValidation, current.tag, fieldName))) } if len(orVals) > 1 { current.typeof = typeOr } if len(vals) > 1 { current.param = strings.Replace(strings.Replace(vals[1], utf8HexComma, ",", -1), utf8Pipe, "|", -1) } } current.isBlockEnd = true } } return } func (v *Validate) fetchCacheTag(tag string) *cTag { // find cached tag ctag, found := v.tagCache.Get(tag) if !found { v.tagCache.lock.Lock() defer v.tagCache.lock.Unlock() // could have been multiple trying to access, but once first is done this ensures tag // isn't parsed again. ctag, found = v.tagCache.Get(tag) if !found { ctag, _ = v.parseFieldTagsRecursive(tag, "", "", false) v.tagCache.Set(tag, ctag) } } return ctag } validator-10.4.1/country_codes.go000066400000000000000000000222731374261122600170030ustar00rootroot00000000000000package validator var iso3166_1_alpha2 = map[string]bool{ // see: https://www.iso.org/iso-3166-country-codes.html "AF": true, "AX": true, "AL": true, "DZ": true, "AS": true, "AD": true, "AO": true, "AI": true, "AQ": true, "AG": true, "AR": true, "AM": true, "AW": true, "AU": true, "AT": true, "AZ": true, "BS": true, "BH": true, "BD": true, "BB": true, "BY": true, "BE": true, "BZ": true, "BJ": true, "BM": true, "BT": true, "BO": true, "BQ": true, "BA": true, "BW": true, "BV": true, "BR": true, "IO": true, "BN": true, "BG": true, "BF": true, "BI": true, "KH": true, "CM": true, "CA": true, "CV": true, "KY": true, "CF": true, "TD": true, "CL": true, "CN": true, "CX": true, "CC": true, "CO": true, "KM": true, "CG": true, "CD": true, "CK": true, "CR": true, "CI": true, "HR": true, "CU": true, "CW": true, "CY": true, "CZ": true, "DK": true, "DJ": true, "DM": true, "DO": true, "EC": true, "EG": true, "SV": true, "GQ": true, "ER": true, "EE": true, "ET": true, "FK": true, "FO": true, "FJ": true, "FI": true, "FR": true, "GF": true, "PF": true, "TF": true, "GA": true, "GM": true, "GE": true, "DE": true, "GH": true, "GI": true, "GR": true, "GL": true, "GD": true, "GP": true, "GU": true, "GT": true, "GG": true, "GN": true, "GW": true, "GY": true, "HT": true, "HM": true, "VA": true, "HN": true, "HK": true, "HU": true, "IS": true, "IN": true, "ID": true, "IR": true, "IQ": true, "IE": true, "IM": true, "IL": true, "IT": true, "JM": true, "JP": true, "JE": true, "JO": true, "KZ": true, "KE": true, "KI": true, "KP": true, "KR": true, "KW": true, "KG": true, "LA": true, "LV": true, "LB": true, "LS": true, "LR": true, "LY": true, "LI": true, "LT": true, "LU": true, "MO": true, "MK": true, "MG": true, "MW": true, "MY": true, "MV": true, "ML": true, "MT": true, "MH": true, "MQ": true, "MR": true, "MU": true, "YT": true, "MX": true, "FM": true, "MD": true, "MC": true, "MN": true, "ME": true, "MS": true, "MA": true, "MZ": true, "MM": true, "NA": true, "NR": true, "NP": true, "NL": true, "NC": true, "NZ": true, "NI": true, "NE": true, "NG": true, "NU": true, "NF": true, "MP": true, "NO": true, "OM": true, "PK": true, "PW": true, "PS": true, "PA": true, "PG": true, "PY": true, "PE": true, "PH": true, "PN": true, "PL": true, "PT": true, "PR": true, "QA": true, "RE": true, "RO": true, "RU": true, "RW": true, "BL": true, "SH": true, "KN": true, "LC": true, "MF": true, "PM": true, "VC": true, "WS": true, "SM": true, "ST": true, "SA": true, "SN": true, "RS": true, "SC": true, "SL": true, "SG": true, "SX": true, "SK": true, "SI": true, "SB": true, "SO": true, "ZA": true, "GS": true, "SS": true, "ES": true, "LK": true, "SD": true, "SR": true, "SJ": true, "SZ": true, "SE": true, "CH": true, "SY": true, "TW": true, "TJ": true, "TZ": true, "TH": true, "TL": true, "TG": true, "TK": true, "TO": true, "TT": true, "TN": true, "TR": true, "TM": true, "TC": true, "TV": true, "UG": true, "UA": true, "AE": true, "GB": true, "US": true, "UM": true, "UY": true, "UZ": true, "VU": true, "VE": true, "VN": true, "VG": true, "VI": true, "WF": true, "EH": true, "YE": true, "ZM": true, "ZW": true, } var iso3166_1_alpha3 = map[string]bool{ // see: https://www.iso.org/iso-3166-country-codes.html "AFG": true, "ALB": true, "DZA": true, "ASM": true, "AND": true, "AGO": true, "AIA": true, "ATA": true, "ATG": true, "ARG": true, "ARM": true, "ABW": true, "AUS": true, "AUT": true, "AZE": true, "BHS": true, "BHR": true, "BGD": true, "BRB": true, "BLR": true, "BEL": true, "BLZ": true, "BEN": true, "BMU": true, "BTN": true, "BOL": true, "BES": true, "BIH": true, "BWA": true, "BVT": true, "BRA": true, "IOT": true, "BRN": true, "BGR": true, "BFA": true, "BDI": true, "CPV": true, "KHM": true, "CMR": true, "CAN": true, "CYM": true, "CAF": true, "TCD": true, "CHL": true, "CHN": true, "CXR": true, "CCK": true, "COL": true, "COM": true, "COD": true, "COG": true, "COK": true, "CRI": true, "HRV": true, "CUB": true, "CUW": true, "CYP": true, "CZE": true, "CIV": true, "DNK": true, "DJI": true, "DMA": true, "DOM": true, "ECU": true, "EGY": true, "SLV": true, "GNQ": true, "ERI": true, "EST": true, "SWZ": true, "ETH": true, "FLK": true, "FRO": true, "FJI": true, "FIN": true, "FRA": true, "GUF": true, "PYF": true, "ATF": true, "GAB": true, "GMB": true, "GEO": true, "DEU": true, "GHA": true, "GIB": true, "GRC": true, "GRL": true, "GRD": true, "GLP": true, "GUM": true, "GTM": true, "GGY": true, "GIN": true, "GNB": true, "GUY": true, "HTI": true, "HMD": true, "VAT": true, "HND": true, "HKG": true, "HUN": true, "ISL": true, "IND": true, "IDN": true, "IRN": true, "IRQ": true, "IRL": true, "IMN": true, "ISR": true, "ITA": true, "JAM": true, "JPN": true, "JEY": true, "JOR": true, "KAZ": true, "KEN": true, "KIR": true, "PRK": true, "KOR": true, "KWT": true, "KGZ": true, "LAO": true, "LVA": true, "LBN": true, "LSO": true, "LBR": true, "LBY": true, "LIE": true, "LTU": true, "LUX": true, "MAC": true, "MDG": true, "MWI": true, "MYS": true, "MDV": true, "MLI": true, "MLT": true, "MHL": true, "MTQ": true, "MRT": true, "MUS": true, "MYT": true, "MEX": true, "FSM": true, "MDA": true, "MCO": true, "MNG": true, "MNE": true, "MSR": true, "MAR": true, "MOZ": true, "MMR": true, "NAM": true, "NRU": true, "NPL": true, "NLD": true, "NCL": true, "NZL": true, "NIC": true, "NER": true, "NGA": true, "NIU": true, "NFK": true, "MKD": true, "MNP": true, "NOR": true, "OMN": true, "PAK": true, "PLW": true, "PSE": true, "PAN": true, "PNG": true, "PRY": true, "PER": true, "PHL": true, "PCN": true, "POL": true, "PRT": true, "PRI": true, "QAT": true, "ROU": true, "RUS": true, "RWA": true, "REU": true, "BLM": true, "SHN": true, "KNA": true, "LCA": true, "MAF": true, "SPM": true, "VCT": true, "WSM": true, "SMR": true, "STP": true, "SAU": true, "SEN": true, "SRB": true, "SYC": true, "SLE": true, "SGP": true, "SXM": true, "SVK": true, "SVN": true, "SLB": true, "SOM": true, "ZAF": true, "SGS": true, "SSD": true, "ESP": true, "LKA": true, "SDN": true, "SUR": true, "SJM": true, "SWE": true, "CHE": true, "SYR": true, "TWN": true, "TJK": true, "TZA": true, "THA": true, "TLS": true, "TGO": true, "TKL": true, "TON": true, "TTO": true, "TUN": true, "TUR": true, "TKM": true, "TCA": true, "TUV": true, "UGA": true, "UKR": true, "ARE": true, "GBR": true, "UMI": true, "USA": true, "URY": true, "UZB": true, "VUT": true, "VEN": true, "VNM": true, "VGB": true, "VIR": true, "WLF": true, "ESH": true, "YEM": true, "ZMB": true, "ZWE": true, "ALA": true, } var iso3166_1_alpha_numeric = map[int]bool{ // see: https://www.iso.org/iso-3166-country-codes.html 4: true, 8: true, 12: true, 16: true, 20: true, 24: true, 660: true, 10: true, 28: true, 32: true, 51: true, 533: true, 36: true, 40: true, 31: true, 44: true, 48: true, 50: true, 52: true, 112: true, 56: true, 84: true, 204: true, 60: true, 64: true, 68: true, 535: true, 70: true, 72: true, 74: true, 76: true, 86: true, 96: true, 100: true, 854: true, 108: true, 132: true, 116: true, 120: true, 124: true, 136: true, 140: true, 148: true, 152: true, 156: true, 162: true, 166: true, 170: true, 174: true, 180: true, 178: true, 184: true, 188: true, 191: true, 192: true, 531: true, 196: true, 203: true, 384: true, 208: true, 262: true, 212: true, 214: true, 218: true, 818: true, 222: true, 226: true, 232: true, 233: true, 748: true, 231: true, 238: true, 234: true, 242: true, 246: true, 250: true, 254: true, 258: true, 260: true, 266: true, 270: true, 268: true, 276: true, 288: true, 292: true, 300: true, 304: true, 308: true, 312: true, 316: true, 320: true, 831: true, 324: true, 624: true, 328: true, 332: true, 334: true, 336: true, 340: true, 344: true, 348: true, 352: true, 356: true, 360: true, 364: true, 368: true, 372: true, 833: true, 376: true, 380: true, 388: true, 392: true, 832: true, 400: true, 398: true, 404: true, 296: true, 408: true, 410: true, 414: true, 417: true, 418: true, 428: true, 422: true, 426: true, 430: true, 434: true, 438: true, 440: true, 442: true, 446: true, 450: true, 454: true, 458: true, 462: true, 466: true, 470: true, 584: true, 474: true, 478: true, 480: true, 175: true, 484: true, 583: true, 498: true, 492: true, 496: true, 499: true, 500: true, 504: true, 508: true, 104: true, 516: true, 520: true, 524: true, 528: true, 540: true, 554: true, 558: true, 562: true, 566: true, 570: true, 574: true, 807: true, 580: true, 578: true, 512: true, 586: true, 585: true, 275: true, 591: true, 598: true, 600: true, 604: true, 608: true, 612: true, 616: true, 620: true, 630: true, 634: true, 642: true, 643: true, 646: true, 638: true, 652: true, 654: true, 659: true, 662: true, 663: true, 666: true, 670: true, 882: true, 674: true, 678: true, 682: true, 686: true, 688: true, 690: true, 694: true, 702: true, 534: true, 703: true, 705: true, 90: true, 706: true, 710: true, 239: true, 728: true, 724: true, 144: true, 729: true, 740: true, 744: true, 752: true, 756: true, 760: true, 158: true, 762: true, 834: true, 764: true, 626: true, 768: true, 772: true, 776: true, 780: true, 788: true, 792: true, 795: true, 796: true, 798: true, 800: true, 804: true, 784: true, 826: true, 581: true, 840: true, 858: true, 860: true, 548: true, 862: true, 704: true, 92: true, 850: true, 876: true, 732: true, 887: true, 894: true, 716: true, 248: true, } validator-10.4.1/doc.go000066400000000000000000001015121374261122600146620ustar00rootroot00000000000000/* Package validator implements value validations for structs and individual fields based on tags. It can also handle Cross-Field and Cross-Struct validation for nested structs and has the ability to dive into arrays and maps of any type. see more examples https://github.com/go-playground/validator/tree/master/_examples Validation Functions Return Type error Doing things this way is actually the way the standard library does, see the file.Open method here: https://golang.org/pkg/os/#Open. The authors return type "error" to avoid the issue discussed in the following, where err is always != nil: http://stackoverflow.com/a/29138676/3158232 https://github.com/go-playground/validator/issues/134 Validator only InvalidValidationError for bad validation input, nil or ValidationErrors as type error; so, in your code all you need to do is check if the error returned is not nil, and if it's not check if error is InvalidValidationError ( if necessary, most of the time it isn't ) type cast it to type ValidationErrors like so err.(validator.ValidationErrors). Custom Validation Functions Custom Validation functions can be added. Example: // Structure func customFunc(fl validator.FieldLevel) bool { if fl.Field().String() == "invalid" { return false } return true } validate.RegisterValidation("custom tag name", customFunc) // NOTES: using the same tag name as an existing function // will overwrite the existing one Cross-Field Validation Cross-Field Validation can be done via the following tags: - eqfield - nefield - gtfield - gtefield - ltfield - ltefield - eqcsfield - necsfield - gtcsfield - gtecsfield - ltcsfield - ltecsfield If, however, some custom cross-field validation is required, it can be done using a custom validation. Why not just have cross-fields validation tags (i.e. only eqcsfield and not eqfield)? The reason is efficiency. If you want to check a field within the same struct "eqfield" only has to find the field on the same struct (1 level). But, if we used "eqcsfield" it could be multiple levels down. Example: type Inner struct { StartDate time.Time } type Outer struct { InnerStructField *Inner CreatedAt time.Time `validate:"ltecsfield=InnerStructField.StartDate"` } now := time.Now() inner := &Inner{ StartDate: now, } outer := &Outer{ InnerStructField: inner, CreatedAt: now, } errs := validate.Struct(outer) // NOTE: when calling validate.Struct(val) topStruct will be the top level struct passed // into the function // when calling validate.VarWithValue(val, field, tag) val will be // whatever you pass, struct, field... // when calling validate.Field(field, tag) val will be nil Multiple Validators Multiple validators on a field will process in the order defined. Example: type Test struct { Field `validate:"max=10,min=1"` } // max will be checked then min Bad Validator definitions are not handled by the library. Example: type Test struct { Field `validate:"min=10,max=0"` } // this definition of min max will never succeed Using Validator Tags Baked In Cross-Field validation only compares fields on the same struct. If Cross-Field + Cross-Struct validation is needed you should implement your own custom validator. Comma (",") is the default separator of validation tags. If you wish to have a comma included within the parameter (i.e. excludesall=,) you will need to use the UTF-8 hex representation 0x2C, which is replaced in the code as a comma, so the above will become excludesall=0x2C. type Test struct { Field `validate:"excludesall=,"` // BAD! Do not include a comma. Field `validate:"excludesall=0x2C"` // GOOD! Use the UTF-8 hex representation. } Pipe ("|") is the 'or' validation tags deparator. If you wish to have a pipe included within the parameter i.e. excludesall=| you will need to use the UTF-8 hex representation 0x7C, which is replaced in the code as a pipe, so the above will become excludesall=0x7C type Test struct { Field `validate:"excludesall=|"` // BAD! Do not include a a pipe! Field `validate:"excludesall=0x7C"` // GOOD! Use the UTF-8 hex representation. } Baked In Validators and Tags Here is a list of the current built in validators: Skip Field Tells the validation to skip this struct field; this is particularly handy in ignoring embedded structs from being validated. (Usage: -) Usage: - Or Operator This is the 'or' operator allowing multiple validators to be used and accepted. (Usage: rgb|rgba) <-- this would allow either rgb or rgba colors to be accepted. This can also be combined with 'and' for example ( Usage: omitempty,rgb|rgba) Usage: | StructOnly When a field that is a nested struct is encountered, and contains this flag any validation on the nested struct will be run, but none of the nested struct fields will be validated. This is useful if inside of your program you know the struct will be valid, but need to verify it has been assigned. NOTE: only "required" and "omitempty" can be used on a struct itself. Usage: structonly NoStructLevel Same as structonly tag except that any struct level validations will not run. Usage: nostructlevel Omit Empty Allows conditional validation, for example if a field is not set with a value (Determined by the "required" validator) then other validation such as min or max won't run, but if a value is set validation will run. Usage: omitempty Dive This tells the validator to dive into a slice, array or map and validate that level of the slice, array or map with the validation tags that follow. Multidimensional nesting is also supported, each level you wish to dive will require another dive tag. dive has some sub-tags, 'keys' & 'endkeys', please see the Keys & EndKeys section just below. Usage: dive Example #1 [][]string with validation tag "gt=0,dive,len=1,dive,required" // gt=0 will be applied to [] // len=1 will be applied to []string // required will be applied to string Example #2 [][]string with validation tag "gt=0,dive,dive,required" // gt=0 will be applied to [] // []string will be spared validation // required will be applied to string Keys & EndKeys These are to be used together directly after the dive tag and tells the validator that anything between 'keys' and 'endkeys' applies to the keys of a map and not the values; think of it like the 'dive' tag, but for map keys instead of values. Multidimensional nesting is also supported, each level you wish to validate will require another 'keys' and 'endkeys' tag. These tags are only valid for maps. Usage: dive,keys,othertagvalidation(s),endkeys,valuevalidationtags Example #1 map[string]string with validation tag "gt=0,dive,keys,eg=1|eq=2,endkeys,required" // gt=0 will be applied to the map itself // eg=1|eq=2 will be applied to the map keys // required will be applied to map values Example #2 map[[2]string]string with validation tag "gt=0,dive,keys,dive,eq=1|eq=2,endkeys,required" // gt=0 will be applied to the map itself // eg=1|eq=2 will be applied to each array element in the the map keys // required will be applied to map values Required This validates that the value is not the data types default zero value. For numbers ensures value is not zero. For strings ensures value is not "". For slices, maps, pointers, interfaces, channels and functions ensures the value is not nil. Usage: required Required If The field under validation must be present and not empty only if all the other specified fields are equal to the value following the specified field. For strings ensures value is not "". For slices, maps, pointers, interfaces, channels and functions ensures the value is not nil. Usage: required_if Examples: // require the field if the Field1 is equal to the parameter given: Usage: required_if=Field1 foobar // require the field if the Field1 and Field2 is equal to the value respectively: Usage: required_if=Field1 foo Field2 bar Required Unless The field under validation must be present and not empty unless all the other specified fields are equal to the value following the specified field. For strings ensures value is not "". For slices, maps, pointers, interfaces, channels and functions ensures the value is not nil. Usage: required_unless Examples: // require the field unless the Field1 is equal to the parameter given: Usage: required_unless=Field1 foobar // require the field unless the Field1 and Field2 is equal to the value respectively: Usage: required_unless=Field1 foo Field2 bar Required With The field under validation must be present and not empty only if any of the other specified fields are present. For strings ensures value is not "". For slices, maps, pointers, interfaces, channels and functions ensures the value is not nil. Usage: required_with Examples: // require the field if the Field1 is present: Usage: required_with=Field1 // require the field if the Field1 or Field2 is present: Usage: required_with=Field1 Field2 Required With All The field under validation must be present and not empty only if all of the other specified fields are present. For strings ensures value is not "". For slices, maps, pointers, interfaces, channels and functions ensures the value is not nil. Usage: required_with_all Example: // require the field if the Field1 and Field2 is present: Usage: required_with_all=Field1 Field2 Required Without The field under validation must be present and not empty only when any of the other specified fields are not present. For strings ensures value is not "". For slices, maps, pointers, interfaces, channels and functions ensures the value is not nil. Usage: required_without Examples: // require the field if the Field1 is not present: Usage: required_without=Field1 // require the field if the Field1 or Field2 is not present: Usage: required_without=Field1 Field2 Required Without All The field under validation must be present and not empty only when all of the other specified fields are not present. For strings ensures value is not "". For slices, maps, pointers, interfaces, channels and functions ensures the value is not nil. Usage: required_without_all Example: // require the field if the Field1 and Field2 is not present: Usage: required_without_all=Field1 Field2 Is Default This validates that the value is the default value and is almost the opposite of required. Usage: isdefault Length For numbers, length will ensure that the value is equal to the parameter given. For strings, it checks that the string length is exactly that number of characters. For slices, arrays, and maps, validates the number of items. Example #1 Usage: len=10 Example #2 (time.Duration) For time.Duration, len will ensure that the value is equal to the duration given in the parameter. Usage: len=1h30m Maximum For numbers, max will ensure that the value is less than or equal to the parameter given. For strings, it checks that the string length is at most that number of characters. For slices, arrays, and maps, validates the number of items. Example #1 Usage: max=10 Example #2 (time.Duration) For time.Duration, max will ensure that the value is less than or equal to the duration given in the parameter. Usage: max=1h30m Minimum For numbers, min will ensure that the value is greater or equal to the parameter given. For strings, it checks that the string length is at least that number of characters. For slices, arrays, and maps, validates the number of items. Example #1 Usage: min=10 Example #2 (time.Duration) For time.Duration, min will ensure that the value is greater than or equal to the duration given in the parameter. Usage: min=1h30m Equals For strings & numbers, eq will ensure that the value is equal to the parameter given. For slices, arrays, and maps, validates the number of items. Example #1 Usage: eq=10 Example #2 (time.Duration) For time.Duration, eq will ensure that the value is equal to the duration given in the parameter. Usage: eq=1h30m Not Equal For strings & numbers, ne will ensure that the value is not equal to the parameter given. For slices, arrays, and maps, validates the number of items. Example #1 Usage: ne=10 Example #2 (time.Duration) For time.Duration, ne will ensure that the value is not equal to the duration given in the parameter. Usage: ne=1h30m One Of For strings, ints, and uints, oneof will ensure that the value is one of the values in the parameter. The parameter should be a list of values separated by whitespace. Values may be strings or numbers. To match strings with spaces in them, include the target string between single quotes. Usage: oneof=red green oneof='red green' 'blue yellow' oneof=5 7 9 Greater Than For numbers, this will ensure that the value is greater than the parameter given. For strings, it checks that the string length is greater than that number of characters. For slices, arrays and maps it validates the number of items. Example #1 Usage: gt=10 Example #2 (time.Time) For time.Time ensures the time value is greater than time.Now.UTC(). Usage: gt Example #3 (time.Duration) For time.Duration, gt will ensure that the value is greater than the duration given in the parameter. Usage: gt=1h30m Greater Than or Equal Same as 'min' above. Kept both to make terminology with 'len' easier. Example #1 Usage: gte=10 Example #2 (time.Time) For time.Time ensures the time value is greater than or equal to time.Now.UTC(). Usage: gte Example #3 (time.Duration) For time.Duration, gte will ensure that the value is greater than or equal to the duration given in the parameter. Usage: gte=1h30m Less Than For numbers, this will ensure that the value is less than the parameter given. For strings, it checks that the string length is less than that number of characters. For slices, arrays, and maps it validates the number of items. Example #1 Usage: lt=10 Example #2 (time.Time) For time.Time ensures the time value is less than time.Now.UTC(). Usage: lt Example #3 (time.Duration) For time.Duration, lt will ensure that the value is less than the duration given in the parameter. Usage: lt=1h30m Less Than or Equal Same as 'max' above. Kept both to make terminology with 'len' easier. Example #1 Usage: lte=10 Example #2 (time.Time) For time.Time ensures the time value is less than or equal to time.Now.UTC(). Usage: lte Example #3 (time.Duration) For time.Duration, lte will ensure that the value is less than or equal to the duration given in the parameter. Usage: lte=1h30m Field Equals Another Field This will validate the field value against another fields value either within a struct or passed in field. Example #1: // Validation on Password field using: Usage: eqfield=ConfirmPassword Example #2: // Validating by field: validate.VarWithValue(password, confirmpassword, "eqfield") Field Equals Another Field (relative) This does the same as eqfield except that it validates the field provided relative to the top level struct. Usage: eqcsfield=InnerStructField.Field) Field Does Not Equal Another Field This will validate the field value against another fields value either within a struct or passed in field. Examples: // Confirm two colors are not the same: // // Validation on Color field: Usage: nefield=Color2 // Validating by field: validate.VarWithValue(color1, color2, "nefield") Field Does Not Equal Another Field (relative) This does the same as nefield except that it validates the field provided relative to the top level struct. Usage: necsfield=InnerStructField.Field Field Greater Than Another Field Only valid for Numbers, time.Duration and time.Time types, this will validate the field value against another fields value either within a struct or passed in field. usage examples are for validation of a Start and End date: Example #1: // Validation on End field using: validate.Struct Usage(gtfield=Start) Example #2: // Validating by field: validate.VarWithValue(start, end, "gtfield") Field Greater Than Another Relative Field This does the same as gtfield except that it validates the field provided relative to the top level struct. Usage: gtcsfield=InnerStructField.Field Field Greater Than or Equal To Another Field Only valid for Numbers, time.Duration and time.Time types, this will validate the field value against another fields value either within a struct or passed in field. usage examples are for validation of a Start and End date: Example #1: // Validation on End field using: validate.Struct Usage(gtefield=Start) Example #2: // Validating by field: validate.VarWithValue(start, end, "gtefield") Field Greater Than or Equal To Another Relative Field This does the same as gtefield except that it validates the field provided relative to the top level struct. Usage: gtecsfield=InnerStructField.Field Less Than Another Field Only valid for Numbers, time.Duration and time.Time types, this will validate the field value against another fields value either within a struct or passed in field. usage examples are for validation of a Start and End date: Example #1: // Validation on End field using: validate.Struct Usage(ltfield=Start) Example #2: // Validating by field: validate.VarWithValue(start, end, "ltfield") Less Than Another Relative Field This does the same as ltfield except that it validates the field provided relative to the top level struct. Usage: ltcsfield=InnerStructField.Field Less Than or Equal To Another Field Only valid for Numbers, time.Duration and time.Time types, this will validate the field value against another fields value either within a struct or passed in field. usage examples are for validation of a Start and End date: Example #1: // Validation on End field using: validate.Struct Usage(ltefield=Start) Example #2: // Validating by field: validate.VarWithValue(start, end, "ltefield") Less Than or Equal To Another Relative Field This does the same as ltefield except that it validates the field provided relative to the top level struct. Usage: ltecsfield=InnerStructField.Field Field Contains Another Field This does the same as contains except for struct fields. It should only be used with string types. See the behavior of reflect.Value.String() for behavior on other types. Usage: containsfield=InnerStructField.Field Field Excludes Another Field This does the same as excludes except for struct fields. It should only be used with string types. See the behavior of reflect.Value.String() for behavior on other types. Usage: excludesfield=InnerStructField.Field Unique For arrays & slices, unique will ensure that there are no duplicates. For maps, unique will ensure that there are no duplicate values. For slices of struct, unique will ensure that there are no duplicate values in a field of the struct specified via a parameter. // For arrays, slices, and maps: Usage: unique // For slices of struct: Usage: unique=field Alpha Only This validates that a string value contains ASCII alpha characters only Usage: alpha Alphanumeric This validates that a string value contains ASCII alphanumeric characters only Usage: alphanum Alpha Unicode This validates that a string value contains unicode alpha characters only Usage: alphaunicode Alphanumeric Unicode This validates that a string value contains unicode alphanumeric characters only Usage: alphanumunicode Number This validates that a string value contains number values only. For integers or float it returns true. Usage: number Numeric This validates that a string value contains a basic numeric value. basic excludes exponents etc... for integers or float it returns true. Usage: numeric Hexadecimal String This validates that a string value contains a valid hexadecimal. Usage: hexadecimal Hexcolor String This validates that a string value contains a valid hex color including hashtag (#) Usage: hexcolor Lowercase String This validates that a string value contains only lowercase characters. An empty string is not a valid lowercase string. Usage: lowercase Uppercase String This validates that a string value contains only uppercase characters. An empty string is not a valid uppercase string. Usage: uppercase RGB String This validates that a string value contains a valid rgb color Usage: rgb RGBA String This validates that a string value contains a valid rgba color Usage: rgba HSL String This validates that a string value contains a valid hsl color Usage: hsl HSLA String This validates that a string value contains a valid hsla color Usage: hsla E.164 Phone Number String This validates that a string value contains a valid E.164 Phone number https://en.wikipedia.org/wiki/E.164 (ex. +1123456789) Usage: e164 E-mail String This validates that a string value contains a valid email This may not conform to all possibilities of any rfc standard, but neither does any email provider accept all possibilities. Usage: email JSON String This validates that a string value is valid JSON Usage: json File path This validates that a string value contains a valid file path and that the file exists on the machine. This is done using os.Stat, which is a platform independent function. Usage: file URL String This validates that a string value contains a valid url This will accept any url the golang request uri accepts but must contain a schema for example http:// or rtmp:// Usage: url URI String This validates that a string value contains a valid uri This will accept any uri the golang request uri accepts Usage: uri Urn RFC 2141 String This validataes that a string value contains a valid URN according to the RFC 2141 spec. Usage: urn_rfc2141 Base64 String This validates that a string value contains a valid base64 value. Although an empty string is valid base64 this will report an empty string as an error, if you wish to accept an empty string as valid you can use this with the omitempty tag. Usage: base64 Base64URL String This validates that a string value contains a valid base64 URL safe value according the the RFC4648 spec. Although an empty string is a valid base64 URL safe value, this will report an empty string as an error, if you wish to accept an empty string as valid you can use this with the omitempty tag. Usage: base64url Bitcoin Address This validates that a string value contains a valid bitcoin address. The format of the string is checked to ensure it matches one of the three formats P2PKH, P2SH and performs checksum validation. Usage: btc_addr Bitcoin Bech32 Address (segwit) This validates that a string value contains a valid bitcoin Bech32 address as defined by bip-0173 (https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki) Special thanks to Pieter Wuille for providng reference implementations. Usage: btc_addr_bech32 Ethereum Address This validates that a string value contains a valid ethereum address. The format of the string is checked to ensure it matches the standard Ethereum address format. Usage: eth_addr Contains This validates that a string value contains the substring value. Usage: contains=@ Contains Any This validates that a string value contains any Unicode code points in the substring value. Usage: containsany=!@#? Contains Rune This validates that a string value contains the supplied rune value. Usage: containsrune=@ Excludes This validates that a string value does not contain the substring value. Usage: excludes=@ Excludes All This validates that a string value does not contain any Unicode code points in the substring value. Usage: excludesall=!@#? Excludes Rune This validates that a string value does not contain the supplied rune value. Usage: excludesrune=@ Starts With This validates that a string value starts with the supplied string value Usage: startswith=hello Ends With This validates that a string value ends with the supplied string value Usage: endswith=goodbye Does Not Start With This validates that a string value does not start with the supplied string value Usage: startsnotwith=hello Does Not End With This validates that a string value does not end with the supplied string value Usage: endsnotwith=goodbye International Standard Book Number This validates that a string value contains a valid isbn10 or isbn13 value. Usage: isbn International Standard Book Number 10 This validates that a string value contains a valid isbn10 value. Usage: isbn10 International Standard Book Number 13 This validates that a string value contains a valid isbn13 value. Usage: isbn13 Universally Unique Identifier UUID This validates that a string value contains a valid UUID. Uppercase UUID values will not pass - use `uuid_rfc4122` instead. Usage: uuid Universally Unique Identifier UUID v3 This validates that a string value contains a valid version 3 UUID. Uppercase UUID values will not pass - use `uuid3_rfc4122` instead. Usage: uuid3 Universally Unique Identifier UUID v4 This validates that a string value contains a valid version 4 UUID. Uppercase UUID values will not pass - use `uuid4_rfc4122` instead. Usage: uuid4 Universally Unique Identifier UUID v5 This validates that a string value contains a valid version 5 UUID. Uppercase UUID values will not pass - use `uuid5_rfc4122` instead. Usage: uuid5 ASCII This validates that a string value contains only ASCII characters. NOTE: if the string is blank, this validates as true. Usage: ascii Printable ASCII This validates that a string value contains only printable ASCII characters. NOTE: if the string is blank, this validates as true. Usage: printascii Multi-Byte Characters This validates that a string value contains one or more multibyte characters. NOTE: if the string is blank, this validates as true. Usage: multibyte Data URL This validates that a string value contains a valid DataURI. NOTE: this will also validate that the data portion is valid base64 Usage: datauri Latitude This validates that a string value contains a valid latitude. Usage: latitude Longitude This validates that a string value contains a valid longitude. Usage: longitude Social Security Number SSN This validates that a string value contains a valid U.S. Social Security Number. Usage: ssn Internet Protocol Address IP This validates that a string value contains a valid IP Address. Usage: ip Internet Protocol Address IPv4 This validates that a string value contains a valid v4 IP Address. Usage: ipv4 Internet Protocol Address IPv6 This validates that a string value contains a valid v6 IP Address. Usage: ipv6 Classless Inter-Domain Routing CIDR This validates that a string value contains a valid CIDR Address. Usage: cidr Classless Inter-Domain Routing CIDRv4 This validates that a string value contains a valid v4 CIDR Address. Usage: cidrv4 Classless Inter-Domain Routing CIDRv6 This validates that a string value contains a valid v6 CIDR Address. Usage: cidrv6 Transmission Control Protocol Address TCP This validates that a string value contains a valid resolvable TCP Address. Usage: tcp_addr Transmission Control Protocol Address TCPv4 This validates that a string value contains a valid resolvable v4 TCP Address. Usage: tcp4_addr Transmission Control Protocol Address TCPv6 This validates that a string value contains a valid resolvable v6 TCP Address. Usage: tcp6_addr User Datagram Protocol Address UDP This validates that a string value contains a valid resolvable UDP Address. Usage: udp_addr User Datagram Protocol Address UDPv4 This validates that a string value contains a valid resolvable v4 UDP Address. Usage: udp4_addr User Datagram Protocol Address UDPv6 This validates that a string value contains a valid resolvable v6 UDP Address. Usage: udp6_addr Internet Protocol Address IP This validates that a string value contains a valid resolvable IP Address. Usage: ip_addr Internet Protocol Address IPv4 This validates that a string value contains a valid resolvable v4 IP Address. Usage: ip4_addr Internet Protocol Address IPv6 This validates that a string value contains a valid resolvable v6 IP Address. Usage: ip6_addr Unix domain socket end point Address This validates that a string value contains a valid Unix Address. Usage: unix_addr Media Access Control Address MAC This validates that a string value contains a valid MAC Address. Usage: mac Note: See Go's ParseMAC for accepted formats and types: http://golang.org/src/net/mac.go?s=866:918#L29 Hostname RFC 952 This validates that a string value is a valid Hostname according to RFC 952 https://tools.ietf.org/html/rfc952 Usage: hostname Hostname RFC 1123 This validates that a string value is a valid Hostname according to RFC 1123 https://tools.ietf.org/html/rfc1123 Usage: hostname_rfc1123 or if you want to continue to use 'hostname' in your tags, create an alias. Full Qualified Domain Name (FQDN) This validates that a string value contains a valid FQDN. Usage: fqdn HTML Tags This validates that a string value appears to be an HTML element tag including those described at https://developer.mozilla.org/en-US/docs/Web/HTML/Element Usage: html HTML Encoded This validates that a string value is a proper character reference in decimal or hexadecimal format Usage: html_encoded URL Encoded This validates that a string value is percent-encoded (URL encoded) according to https://tools.ietf.org/html/rfc3986#section-2.1 Usage: url_encoded Directory This validates that a string value contains a valid directory and that it exists on the machine. This is done using os.Stat, which is a platform independent function. Usage: dir HostPort This validates that a string value contains a valid DNS hostname and port that can be used to valiate fields typically passed to sockets and connections. Usage: hostname_port Datetime This validates that a string value is a valid datetime based on the supplied datetime format. Supplied format must match the official Go time format layout as documented in https://golang.org/pkg/time/ Usage: datetime=2006-01-02 Iso3166-1 alpha-2 This validates that a string value is a valid country code based on iso3166-1 alpha-2 standard. see: https://www.iso.org/iso-3166-country-codes.html Usage: iso3166_1_alpha2 Iso3166-1 alpha-3 This validates that a string value is a valid country code based on iso3166-1 alpha-3 standard. see: https://www.iso.org/iso-3166-country-codes.html Usage: iso3166_1_alpha3 Iso3166-1 alpha-numeric This validates that a string value is a valid country code based on iso3166-1 alpha-numeric standard. see: https://www.iso.org/iso-3166-country-codes.html Usage: iso3166_1_alpha3 TimeZone This validates that a string value is a valid time zone based on the time zone database present on the system. Although empty value and Local value are allowed by time.LoadLocation golang function, they are not allowed by this validator. More information on https://golang.org/pkg/time/#LoadLocation Usage: timezone Alias Validators and Tags NOTE: When returning an error, the tag returned in "FieldError" will be the alias tag unless the dive tag is part of the alias. Everything after the dive tag is not reported as the alias tag. Also, the "ActualTag" in the before case will be the actual tag within the alias that failed. Here is a list of the current built in alias tags: "iscolor" alias is "hexcolor|rgb|rgba|hsl|hsla" (Usage: iscolor) "country_code" alias is "iso3166_1_alpha2|iso3166_1_alpha3|iso3166_1_alpha_numeric" (Usage: country_code) Validator notes: regex a regex validator won't be added because commas and = signs can be part of a regex which conflict with the validation definitions. Although workarounds can be made, they take away from using pure regex's. Furthermore it's quick and dirty but the regex's become harder to maintain and are not reusable, so it's as much a programming philosophy as anything. In place of this new validator functions should be created; a regex can be used within the validator function and even be precompiled for better efficiency within regexes.go. And the best reason, you can submit a pull request and we can keep on adding to the validation library of this package! Non standard validators A collection of validation rules that are frequently needed but are more complex than the ones found in the baked in validators. A non standard validator must be registered manually like you would with your own custom validation functions. Example of registration and use: type Test struct { TestField string `validate:"yourtag"` } t := &Test{ TestField: "Test" } validate := validator.New() validate.RegisterValidation("yourtag", validators.NotBlank) Here is a list of the current non standard validators: NotBlank This validates that the value is not blank or with length zero. For strings ensures they do not contain only spaces. For channels, maps, slices and arrays ensures they don't have zero length. For others, a non empty value is required. Usage: notblank Panics This package panics when bad input is provided, this is by design, bad code like that should not make it to production. type Test struct { TestField string `validate:"nonexistantfunction=1"` } t := &Test{ TestField: "Test" } validate.Struct(t) // this will panic */ package validator validator-10.4.1/errors.go000066400000000000000000000163351374261122600154410ustar00rootroot00000000000000package validator import ( "bytes" "fmt" "reflect" "strings" ut "github.com/go-playground/universal-translator" ) const ( fieldErrMsg = "Key: '%s' Error:Field validation for '%s' failed on the '%s' tag" ) // ValidationErrorsTranslations is the translation return type type ValidationErrorsTranslations map[string]string // InvalidValidationError describes an invalid argument passed to // `Struct`, `StructExcept`, StructPartial` or `Field` type InvalidValidationError struct { Type reflect.Type } // Error returns InvalidValidationError message func (e *InvalidValidationError) Error() string { if e.Type == nil { return "validator: (nil)" } return "validator: (nil " + e.Type.String() + ")" } // ValidationErrors is an array of FieldError's // for use in custom error messages post validation. type ValidationErrors []FieldError // Error is intended for use in development + debugging and not intended to be a production error message. // It allows ValidationErrors to subscribe to the Error interface. // All information to create an error message specific to your application is contained within // the FieldError found within the ValidationErrors array func (ve ValidationErrors) Error() string { buff := bytes.NewBufferString("") var fe *fieldError for i := 0; i < len(ve); i++ { fe = ve[i].(*fieldError) buff.WriteString(fe.Error()) buff.WriteString("\n") } return strings.TrimSpace(buff.String()) } // Translate translates all of the ValidationErrors func (ve ValidationErrors) Translate(ut ut.Translator) ValidationErrorsTranslations { trans := make(ValidationErrorsTranslations) var fe *fieldError for i := 0; i < len(ve); i++ { fe = ve[i].(*fieldError) // // in case an Anonymous struct was used, ensure that the key // // would be 'Username' instead of ".Username" // if len(fe.ns) > 0 && fe.ns[:1] == "." { // trans[fe.ns[1:]] = fe.Translate(ut) // continue // } trans[fe.ns] = fe.Translate(ut) } return trans } // FieldError contains all functions to get error details type FieldError interface { // returns the validation tag that failed. if the // validation was an alias, this will return the // alias name and not the underlying tag that failed. // // eg. alias "iscolor": "hexcolor|rgb|rgba|hsl|hsla" // will return "iscolor" Tag() string // returns the validation tag that failed, even if an // alias the actual tag within the alias will be returned. // If an 'or' validation fails the entire or will be returned. // // eg. alias "iscolor": "hexcolor|rgb|rgba|hsl|hsla" // will return "hexcolor|rgb|rgba|hsl|hsla" ActualTag() string // returns the namespace for the field error, with the tag // name taking precedence over the field's actual name. // // eg. JSON name "User.fname" // // See StructNamespace() for a version that returns actual names. // // NOTE: this field can be blank when validating a single primitive field // using validate.Field(...) as there is no way to extract it's name Namespace() string // returns the namespace for the field error, with the field's // actual name. // // eq. "User.FirstName" see Namespace for comparison // // NOTE: this field can be blank when validating a single primitive field // using validate.Field(...) as there is no way to extract its name StructNamespace() string // returns the fields name with the tag name taking precedence over the // field's actual name. // // eq. JSON name "fname" // see StructField for comparison Field() string // returns the field's actual name from the struct, when able to determine. // // eq. "FirstName" // see Field for comparison StructField() string // returns the actual field's value in case needed for creating the error // message Value() interface{} // returns the param value, in string form for comparison; this will also // help with generating an error message Param() string // Kind returns the Field's reflect Kind // // eg. time.Time's kind is a struct Kind() reflect.Kind // Type returns the Field's reflect Type // // // eg. time.Time's type is time.Time Type() reflect.Type // returns the FieldError's translated error // from the provided 'ut.Translator' and registered 'TranslationFunc' // // NOTE: if no registered translator can be found it returns the same as // calling fe.Error() Translate(ut ut.Translator) string // Error returns the FieldError's message Error() string } // compile time interface checks var _ FieldError = new(fieldError) var _ error = new(fieldError) // fieldError contains a single field's validation error along // with other properties that may be needed for error message creation // it complies with the FieldError interface type fieldError struct { v *Validate tag string actualTag string ns string structNs string fieldLen uint8 structfieldLen uint8 value interface{} param string kind reflect.Kind typ reflect.Type } // Tag returns the validation tag that failed. func (fe *fieldError) Tag() string { return fe.tag } // ActualTag returns the validation tag that failed, even if an // alias the actual tag within the alias will be returned. func (fe *fieldError) ActualTag() string { return fe.actualTag } // Namespace returns the namespace for the field error, with the tag // name taking precedence over the field's actual name. func (fe *fieldError) Namespace() string { return fe.ns } // StructNamespace returns the namespace for the field error, with the field's // actual name. func (fe *fieldError) StructNamespace() string { return fe.structNs } // Field returns the field's name with the tag name taking precedence over the // field's actual name. func (fe *fieldError) Field() string { return fe.ns[len(fe.ns)-int(fe.fieldLen):] // // return fe.field // fld := fe.ns[len(fe.ns)-int(fe.fieldLen):] // log.Println("FLD:", fld) // if len(fld) > 0 && fld[:1] == "." { // return fld[1:] // } // return fld } // returns the field's actual name from the struct, when able to determine. func (fe *fieldError) StructField() string { // return fe.structField return fe.structNs[len(fe.structNs)-int(fe.structfieldLen):] } // Value returns the actual field's value in case needed for creating the error // message func (fe *fieldError) Value() interface{} { return fe.value } // Param returns the param value, in string form for comparison; this will // also help with generating an error message func (fe *fieldError) Param() string { return fe.param } // Kind returns the Field's reflect Kind func (fe *fieldError) Kind() reflect.Kind { return fe.kind } // Type returns the Field's reflect Type func (fe *fieldError) Type() reflect.Type { return fe.typ } // Error returns the fieldError's error message func (fe *fieldError) Error() string { return fmt.Sprintf(fieldErrMsg, fe.ns, fe.Field(), fe.tag) } // Translate returns the FieldError's translated error // from the provided 'ut.Translator' and registered 'TranslationFunc' // // NOTE: if no registered translation can be found, it returns the original // untranslated error message. func (fe *fieldError) Translate(ut ut.Translator) string { m, ok := fe.v.transTagFunc[ut] if !ok { return fe.Error() } fn, ok := m[fe.tag] if !ok { return fe.Error() } return fn(ut, fe) } validator-10.4.1/field_level.go000066400000000000000000000113441374261122600163720ustar00rootroot00000000000000package validator import "reflect" // FieldLevel contains all the information and helper functions // to validate a field type FieldLevel interface { // returns the top level struct, if any Top() reflect.Value // returns the current fields parent struct, if any or // the comparison value if called 'VarWithValue' Parent() reflect.Value // returns current field for validation Field() reflect.Value // returns the field's name with the tag // name taking precedence over the fields actual name. FieldName() string // returns the struct field's name StructFieldName() string // returns param for validation against current field Param() string // GetTag returns the current validations tag name GetTag() string // ExtractType gets the actual underlying type of field value. // It will dive into pointers, customTypes and return you the // underlying value and it's kind. ExtractType(field reflect.Value) (value reflect.Value, kind reflect.Kind, nullable bool) // traverses the parent struct to retrieve a specific field denoted by the provided namespace // in the param and returns the field, field kind and whether is was successful in retrieving // the field at all. // // NOTE: when not successful ok will be false, this can happen when a nested struct is nil and so the field // could not be retrieved because it didn't exist. // // Deprecated: Use GetStructFieldOK2() instead which also return if the value is nullable. GetStructFieldOK() (reflect.Value, reflect.Kind, bool) // GetStructFieldOKAdvanced is the same as GetStructFieldOK except that it accepts the parent struct to start looking for // the field and namespace allowing more extensibility for validators. // // Deprecated: Use GetStructFieldOKAdvanced2() instead which also return if the value is nullable. GetStructFieldOKAdvanced(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool) // traverses the parent struct to retrieve a specific field denoted by the provided namespace // in the param and returns the field, field kind, if it's a nullable type and whether is was successful in retrieving // the field at all. // // NOTE: when not successful ok will be false, this can happen when a nested struct is nil and so the field // could not be retrieved because it didn't exist. GetStructFieldOK2() (reflect.Value, reflect.Kind, bool, bool) // GetStructFieldOKAdvanced is the same as GetStructFieldOK except that it accepts the parent struct to start looking for // the field and namespace allowing more extensibility for validators. GetStructFieldOKAdvanced2(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool, bool) } var _ FieldLevel = new(validate) // Field returns current field for validation func (v *validate) Field() reflect.Value { return v.flField } // FieldName returns the field's name with the tag // name taking precedence over the fields actual name. func (v *validate) FieldName() string { return v.cf.altName } // GetTag returns the current validations tag name func (v *validate) GetTag() string { return v.ct.tag } // StructFieldName returns the struct field's name func (v *validate) StructFieldName() string { return v.cf.name } // Param returns param for validation against current field func (v *validate) Param() string { return v.ct.param } // GetStructFieldOK returns Param returns param for validation against current field // // Deprecated: Use GetStructFieldOK2() instead which also return if the value is nullable. func (v *validate) GetStructFieldOK() (reflect.Value, reflect.Kind, bool) { current, kind, _, found := v.getStructFieldOKInternal(v.slflParent, v.ct.param) return current, kind, found } // GetStructFieldOKAdvanced is the same as GetStructFieldOK except that it accepts the parent struct to start looking for // the field and namespace allowing more extensibility for validators. // // Deprecated: Use GetStructFieldOKAdvanced2() instead which also return if the value is nullable. func (v *validate) GetStructFieldOKAdvanced(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool) { current, kind, _, found := v.GetStructFieldOKAdvanced2(val, namespace) return current, kind, found } // GetStructFieldOK returns Param returns param for validation against current field func (v *validate) GetStructFieldOK2() (reflect.Value, reflect.Kind, bool, bool) { return v.getStructFieldOKInternal(v.slflParent, v.ct.param) } // GetStructFieldOKAdvanced is the same as GetStructFieldOK except that it accepts the parent struct to start looking for // the field and namespace allowing more extensibility for validators. func (v *validate) GetStructFieldOKAdvanced2(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool, bool) { return v.getStructFieldOKInternal(val, namespace) } validator-10.4.1/go.mod000066400000000000000000000004521374261122600146750ustar00rootroot00000000000000module github.com/go-playground/validator/v10 go 1.13 require ( github.com/go-playground/assert/v2 v2.0.1 github.com/go-playground/locales v0.13.0 github.com/go-playground/universal-translator v0.17.0 github.com/leodido/go-urn v1.2.0 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 ) validator-10.4.1/go.sum000066400000000000000000000051111374261122600147170ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= validator-10.4.1/logo.png000066400000000000000000000322031374261122600152340ustar00rootroot00000000000000PNG  IHDR<qsBIT|d pHYs  ~tEXtSoftwareAdobe Fireworks CS6輲 IDATxwEǿ=yg6/,yQEATD1+S99' ;Sp(&T(y 8?gwfمe}>=5]ݿyz)!hkhcXhtbu]A :ՁvA:. V@Xhtbu]A :Ձvmww Y n H2, g€A_5P߀ŷTⱄ  >ޜSdurgd32]4\TcD0a jk"@xkAMi`;(Rw= Pl gWV~=3x{ڥ+ޜN2px9]GhBD@H R"M#% &PVJu*6t*Y E+~[X?C˒JFGdxul %#/Lt)%f4b&HEZlA4m6R,-b׬w?*PĊ#T8ov)}?!m݆ [wt#" # cICw:9]DA,_ƪ9ۧ.+_F? ,u ٳEtGCNAM 0]4]Chz3 CXlN6 ,}-5Ғ{O1eݓ(")e"v{ k4붤 s~>'N!WoZpȪ{Ӊ.^͵ls:ќ.TQS^:L2:uI! `CeKGg)tB׽'{,ᤦxk`ekW!:RJ+~)BRKȲ0ΙJȈRMB\AG{!Z63 tu5`Mqy}x|>tM#`D#먔\nE \Etrt"AqE[B9]7(zJÈ0|]_:uv76}\4 #BMVV_y~]Y[w\IE,K؀!>H7χSYX?X>}5꼋@$MQ/ث*M'jTv\={`D 4려F,U5|>`:uw 7/͏?SOzNH fqgo9dꍿ$͆ӗJ||ߢ?|{)03ɕ4IJHe&d̛vn5hv;`i*Eddr0cWcw: B,h+1vpƏ9!CpP[QNڵ|?>n<8k*]e;}հ3q/͗_!hލJsO<γ} Sg"?RR2X9S{Q{i2zAFF8>3k . I6?%C: ޟy.н V+_PvG|~߭z@eeX2~gn~G\4&q)qgfGa[01<Y (K35ysy/~:YJYN#XIϾ2@Fw80#ay_u!/ PV+5?cgvϝ3a5{UrF!T] 2t޺'M۩~FM>"P^pjg<ſ^*Rtӗ7{oHt$M/Kq,Ǟx|ozy3DY\.uRgc'd*>Zehv{]@ GdB]Nz TYڔy㜓xC՛@: ?7@׼;Չ=zrEy< vm e,.>s |fwԝReܵݧ?e)\]ןh(HV~x; mҡ6Bo#dÈ(OŦ |vH0KԆ~!3=~|t专N{ͫVl1рfy zÛi72` [ 4: dfsU7xFP&vO N_DM$ uNr:(Y;rl'a:x/f$ ncˏsr mQbyrŌo Ecs5uk  y =ň3ϧD:F$PKd`+flRA4&@<D!hOϘqj`-٦}pԛM? Apf2{>ݺRPIUHD)3N+Y@&IJF2EP{rOȳ/ii'ur\6SnpCsN9saiiDm]B%1l] %ER0 |gLvbYXq᏿Z jO<xJ}G~!ZR-!NIAmO r7Ҍۄ4Q#!GORٸG.7Bdd+/O>Z9/>Hbm OjH-F)Y~MtI*vBXx7;0N>TV\i`&TtaS_ tS/ /Tgz&4W{Ql\# )^4_>|" TjmO$ ~w>ft/HOϋy!hu񛘦'-Zl&>c>Lkw8m%؝FI7o)}?`Mb l4EVZբyM>Ss cTo̊_2?C75 IJ87y9FK)_;#~B}Yl_^{utoj:kW3op.Ezy _.[N0%O9ȣ$UU4K~uay}xDU*+GOt?~G)eeۅH bH)Co7>4;t/n7$NѽnP]X'f͚`|\zM4SI0ԉpALź^r1O@ݑd! FO=C#H?Tu(45T@+2)e4Doʿ΃ ' 3Dm_tT¡ gذa6vl=|`D#N^/T\ }Qx|׌{= ӬP(i ~a@4 w kҠt̺_W8FJٍ$3F 8|'<ψF-}۠`!ۮ#pE,yW0ؼl >(k~I\ AJv#8^' sZ_qÏ3W\&e3 j-U7T3 ޣvcTU RJh 76qM7 FJƌ<οxth Yʬ Nr&4MpZ`P[RO<z<{N0q#/Zu .> t8M Z[aD\dʋ- VKa^i](h F$ag]/pGrĉtֽ6n_|۟~FAj6xNHÌܼ ӝЖjфYxUs뽬]ů#˦f0M*2o4Mf#\ȏe;P!{/BlQHJb=|sUH .µyeg}^UUM Fnq1 E5]V,DH 41~yM~= AC!JK)+0759x^pH0H8;.K 5+B^RJI6M͘2yf/Ēn௭`U[ kA^i]Khe {9k4_}}7D t[ΡH.FhSMSn2> TdXNwjZ[ܔ*lP`D#ՕBйGOS7y+ PKCU]#ߟ{1y ^^ݲ3bǏߏ4GdyT5Q-IMIJvN@e V =TNjrʷr9*CG{;>|ɽut0R߻/fD5px)"P$yx9W(Cy,A4qz}2_AR9HND!ub'Bᵿ1՝ B+k #D p8B`H  ѭ39fo6F!ˍwV-ugP9*s3&ʹ*l;,ƽ!XVmʱø+KϠy{{~u,+Wo%k=` 3Cn;h(=@8.v셸ehcU*ޙs&-XT/oHπzO}ˌum !->ߡiq1sA܌7ToC]5h"v{ 18^PhL, % Mi0׳d3\0(^s CW+W =-G#!C'˿R9u1hiU!ovH$s!yVn'UhͨC>?|ygFZ/).w^^ݱ>NJn^0"D$azT!l*y! :* FF>RG5ꬺw-ȠHm2ڷD[¦bʜ;J^; H؈D$@a'ʒˀfGzRؐ>36 MK|Tv]ǴM^RhJZ2P  Z+ޙ2MW>c>˄TR]Q:[j;l2fl ' J,#FC!* :>Y?pm ? KBGm9K}W3o54X7ILdѰ&ܡ;M 0py<M\S>,NUP$i}yTu$R"Ub+&vv*QϮWqhd )%4?X]4SjSe0 d >S&N]TbS9NEIdHJ$%,k[ D%h*iZ-i IKwj YN;vM#b"OeTv8Ma뷏*v$Dd%N $ XPuU nbyZxU_=[9w7؛.A0wSs6l%V8H:r9`w8}i|0dB:ǹv Gq35?/F{:rbe`Jh8ed.[Ɵʷ𷊍ͥps]FHӄwis$ e-BtGVѝW+=+WCϞٸ "NvnW`ƎLk UŁ5ipbV*;7Oh*2uLjDӣB04ܬt;d vU~z x !H)6}J,kI&p.ӑFOntJoPQ(Ι٪V45?|C&&mh`^|qΦwlXN})bTJMqi5TT NƩS&0i>|!FH)]F,k}xO=3ě@h$næiІ4)^LQ,{CՙwϞXMraj۽`n(ᨁtxyP&3S#ic9l6^{~^@i%`HT%*vhF@'=##dCUQj `2/ǐ60G;S/miDpfyx!c,}.,|;ݰ;UajnNƤ)ǎ_?d=+p8M!# Q%FZ4ӨwoM+ƍPPuDzel8ajP *ۅi,e.ye6́#aHE\̩SQ!ķR%;~Vm)EwCrHOTB?)m 띀4һps{C׮0|M))EꏇW~ѽ'a*fM>5=O}7w-'~IVt<}KۤmXUp t͖*^y ?}Eg{<.+dmT4Mz8~=4y/~>6 >*F-U!]0<)݁ˀǁ')@LwRAM>vn#6UT?~>J=^KV^ <jvկmcmq)֭Kzǟ}78EMfC> !z46n%T EjrCl=XD0`#22s+ϙ?~7ܐy VtƹUFm<*ݶ=xFP;;v@JiJ) wZp^-iIDATx}.ۓhpP ޤqƌIzӝw1Xvr;RTD~l|g"'8!u۩&H b5!Dbw[/(+9>xNnpW#AsԻ"@yޟx"jvB쳝;%בͰ\HPZjEJ0f[_O k ?bY$:D8\jM_}Y&vw@*%xNBoHfbe8}n :js;SU'0-U0dH㗼Dm*w?c=Oƨn)DU.:PZ¨ZJ~NVŽ{Hfb|izEB*FG :?w:/,YAAe2xO1 7q,ԇaRFB*:nIt(֡DQ {\#F҄4TSjk}Y WUD"!R33Y1Xu΢GIz~@gQzݬ\r6ز.'/ک,t&f"6ؖ4/J0bBHJbYdJsz}/ G- Lt~qοpN'+ 4*$atY&A7 Kxóet@a.DNQoo5j / !2*$+$p{6öB,QIJT˨amEE1L]sHVbP( &;TalHag0&dWК|.U,Z&YFH[?*B#! 7nKԊ=20>nR=T԰NG*x71Ӛ'("Ş`̇F__kmx}knq.pF,P? Gu1d(+Y\.LgL±OĿtup8JuuM%J ^E7568v,l4+F,0eߡ}zrѝQ_W.-X./?g<]')6Wr%sO9TXPQ Tpu_sG0OB2 %(mraKK6C~ֳIsS/5 >rH PJ4GŖB4'X*I릠Sfʊ|Ơ@.(?S;;wIA,.,l-&=,[ρh@P9u {%rKYLj3/ǰ0"~n`qmN'vw XӜrpo~B MT_~+7u],~AԢlD9JQp򕝹=X:pǾWB(D[ou'?6xO>#FpmnL$ k>ϢǺ58Yٜua˕•f1`\gHNE&v5<ڟ@lsZJUd);{I52;dNɠ\LtDRtd=f}+ͭڼ,Fw^LvRӐRF4R1T44݆pl"Jlx|~ *t`缴4.OC ݦSVY#3>Wn䘉xOֵ~HRAvd(Ig9Yh RA ܋W^͖JF4V*Emm o͞ ڵ\?Ó2˰}t{ܡ{wܮRvGa" )Mo(хfh]GuCH%E䯥dENmIR| |4C9j&w0j _YHZJ}Ai`l|-|~;U[=AOˣ7Lg¡0t/o랋~1Pqk )!4Eʶ E7W^yYi{Ss;=/ۍfuLJcDD TVP[RLM7m$~-ӣ!aBqP/DGJY`ݧܣkG{oG0"Q,\ɳo͡?Q cP PXwe6f1JFT}KwmcO _^[?0nL(/^¥TbͦGQqkQd̍"Z*JKtB͖tfvGÓ⳻n鰹\sLJS`8 @ Wp!8aJ =ԌK)?hfMgw9b0z,{ *I=L&s5QNT5U)9McO 2'k,㉙/ BOf 퀛sMP? ֹ툢fd7 5e uF\Q_8( ϊmF[<R9}k7KC ]@jǛ+N\KCIN}ڒ|<+AnYo,IjgGHxXS!wCBRmG]GgƢjb+a)8b%3Ĥkdwr_w[8>b sV)O֏b1a-$^cQ")voXh)1A :ՁvA:. V@Xhtbu]A :Ձv0IENDB`validator-10.4.1/non-standard/000077500000000000000000000000001374261122600161565ustar00rootroot00000000000000validator-10.4.1/non-standard/validators/000077500000000000000000000000001374261122600203265ustar00rootroot00000000000000validator-10.4.1/non-standard/validators/notblank.go000066400000000000000000000012471374261122600224710ustar00rootroot00000000000000package validators import ( "reflect" "strings" "github.com/go-playground/validator/v10" ) // NotBlank is the validation function for validating if the current field // has a value or length greater than zero, or is not a space only string. func NotBlank(fl validator.FieldLevel) bool { field := fl.Field() switch field.Kind() { case reflect.String: return len(strings.TrimSpace(field.String())) > 0 case reflect.Chan, reflect.Map, reflect.Slice, reflect.Array: return field.Len() > 0 case reflect.Ptr, reflect.Interface, reflect.Func: return !field.IsNil() default: return field.IsValid() && field.Interface() != reflect.Zero(field.Type()).Interface() } } validator-10.4.1/non-standard/validators/notblank_test.go000066400000000000000000000023141374261122600235240ustar00rootroot00000000000000package validators import ( "testing" "github.com/go-playground/validator/v10" "github.com/go-playground/assert/v2" ) type test struct { String string `validate:"notblank"` Array []int `validate:"notblank"` Pointer *int `validate:"notblank"` Number int `validate:"notblank"` Interface interface{} `validate:"notblank"` Func func() `validate:"notblank"` } func TestNotBlank(t *testing.T) { v := validator.New() err := v.RegisterValidation("notblank", NotBlank) assert.Equal(t, nil, err) // Errors var x *int invalid := test{ String: " ", Array: []int{}, Pointer: x, Number: 0, Interface: nil, Func: nil, } fieldsWithError := []string{ "String", "Array", "Pointer", "Number", "Interface", "Func", } errors := v.Struct(invalid).(validator.ValidationErrors) var fields []string for _, err := range errors { fields = append(fields, err.Field()) } assert.Equal(t, fieldsWithError, fields) // No errors y := 1 x = &y valid := test{ String: "str", Array: []int{1}, Pointer: x, Number: 1, Interface: "value", Func: func() {}, } err = v.Struct(valid) assert.Equal(t, nil, err) } validator-10.4.1/regexes.go000066400000000000000000000230611374261122600155610ustar00rootroot00000000000000package validator import "regexp" const ( alphaRegexString = "^[a-zA-Z]+$" alphaNumericRegexString = "^[a-zA-Z0-9]+$" alphaUnicodeRegexString = "^[\\p{L}]+$" alphaUnicodeNumericRegexString = "^[\\p{L}\\p{N}]+$" numericRegexString = "^[-+]?[0-9]+(?:\\.[0-9]+)?$" numberRegexString = "^[0-9]+$" hexadecimalRegexString = "^(0[xX])?[0-9a-fA-F]+$" hexcolorRegexString = "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$" rgbRegexString = "^rgb\\(\\s*(?:(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])|(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%)\\s*\\)$" rgbaRegexString = "^rgba\\(\\s*(?:(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])|(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%)\\s*,\\s*(?:(?:0.[1-9]*)|[01])\\s*\\)$" hslRegexString = "^hsl\\(\\s*(?:0|[1-9]\\d?|[12]\\d\\d|3[0-5]\\d|360)\\s*,\\s*(?:(?:0|[1-9]\\d?|100)%)\\s*,\\s*(?:(?:0|[1-9]\\d?|100)%)\\s*\\)$" hslaRegexString = "^hsla\\(\\s*(?:0|[1-9]\\d?|[12]\\d\\d|3[0-5]\\d|360)\\s*,\\s*(?:(?:0|[1-9]\\d?|100)%)\\s*,\\s*(?:(?:0|[1-9]\\d?|100)%)\\s*,\\s*(?:(?:0.[1-9]*)|[01])\\s*\\)$" emailRegexString = "^(?:(?:(?:(?:[a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+(?:\\.([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+)*)|(?:(?:\\x22)(?:(?:(?:(?:\\x20|\\x09)*(?:\\x0d\\x0a))?(?:\\x20|\\x09)+)?(?:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}]))))*(?:(?:(?:\\x20|\\x09)*(?:\\x0d\\x0a))?(\\x20|\\x09)+)?(?:\\x22))))@(?:(?:(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])(?:[a-zA-Z]|\\d|-|\\.|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.)+(?:(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])(?:[a-zA-Z]|\\d|-|\\.|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.?$" e164RegexString = "^\\+[1-9]?[0-9]{7,14}$" base64RegexString = "^(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+\\/]{3}=|[A-Za-z0-9+\\/]{4})$" base64URLRegexString = "^(?:[A-Za-z0-9-_]{4})*(?:[A-Za-z0-9-_]{2}==|[A-Za-z0-9-_]{3}=|[A-Za-z0-9-_]{4})$" iSBN10RegexString = "^(?:[0-9]{9}X|[0-9]{10})$" iSBN13RegexString = "^(?:(?:97(?:8|9))[0-9]{10})$" uUID3RegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-3[0-9a-f]{3}-[0-9a-f]{4}-[0-9a-f]{12}$" uUID4RegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" uUID5RegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" uUIDRegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$" uUID3RFC4122RegexString = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-3[0-9a-fA-F]{3}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$" uUID4RFC4122RegexString = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$" uUID5RFC4122RegexString = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-5[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$" uUIDRFC4122RegexString = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$" aSCIIRegexString = "^[\x00-\x7F]*$" printableASCIIRegexString = "^[\x20-\x7E]*$" multibyteRegexString = "[^\x00-\x7F]" dataURIRegexString = `^data:((?:\w+\/(?:([^;]|;[^;]).)+)?)` latitudeRegexString = "^[-+]?([1-8]?\\d(\\.\\d+)?|90(\\.0+)?)$" longitudeRegexString = "^[-+]?(180(\\.0+)?|((1[0-7]\\d)|([1-9]?\\d))(\\.\\d+)?)$" sSNRegexString = `^[0-9]{3}[ -]?(0[1-9]|[1-9][0-9])[ -]?([1-9][0-9]{3}|[0-9][1-9][0-9]{2}|[0-9]{2}[1-9][0-9]|[0-9]{3}[1-9])$` hostnameRegexStringRFC952 = `^[a-zA-Z]([a-zA-Z0-9\-]+[\.]?)*[a-zA-Z0-9]$` // https://tools.ietf.org/html/rfc952 hostnameRegexStringRFC1123 = `^([a-zA-Z0-9]{1}[a-zA-Z0-9_-]{0,62}){1}(\.[a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62})*?$` // accepts hostname starting with a digit https://tools.ietf.org/html/rfc1123 fqdnRegexStringRFC1123 = `^([a-zA-Z0-9]{1}[a-zA-Z0-9_-]{0,62})(\.[a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62})*?(\.[a-zA-Z]{1}[a-zA-Z0-9]{0,62})\.?$` // same as hostnameRegexStringRFC1123 but must contain a non numerical TLD (possibly ending with '.') btcAddressRegexString = `^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$` // bitcoin address btcAddressUpperRegexStringBech32 = `^BC1[02-9AC-HJ-NP-Z]{7,76}$` // bitcoin bech32 address https://en.bitcoin.it/wiki/Bech32 btcAddressLowerRegexStringBech32 = `^bc1[02-9ac-hj-np-z]{7,76}$` // bitcoin bech32 address https://en.bitcoin.it/wiki/Bech32 ethAddressRegexString = `^0x[0-9a-fA-F]{40}$` ethAddressUpperRegexString = `^0x[0-9A-F]{40}$` ethAddressLowerRegexString = `^0x[0-9a-f]{40}$` uRLEncodedRegexString = `(%[A-Fa-f0-9]{2})` hTMLEncodedRegexString = `&#[x]?([0-9a-fA-F]{2})|(>)|(<)|(")|(&)+[;]?` hTMLRegexString = `<[/]?([a-zA-Z]+).*?>` splitParamsRegexString = `'[^']*'|\S+` ) var ( alphaRegex = regexp.MustCompile(alphaRegexString) alphaNumericRegex = regexp.MustCompile(alphaNumericRegexString) alphaUnicodeRegex = regexp.MustCompile(alphaUnicodeRegexString) alphaUnicodeNumericRegex = regexp.MustCompile(alphaUnicodeNumericRegexString) numericRegex = regexp.MustCompile(numericRegexString) numberRegex = regexp.MustCompile(numberRegexString) hexadecimalRegex = regexp.MustCompile(hexadecimalRegexString) hexcolorRegex = regexp.MustCompile(hexcolorRegexString) rgbRegex = regexp.MustCompile(rgbRegexString) rgbaRegex = regexp.MustCompile(rgbaRegexString) hslRegex = regexp.MustCompile(hslRegexString) hslaRegex = regexp.MustCompile(hslaRegexString) e164Regex = regexp.MustCompile(e164RegexString) emailRegex = regexp.MustCompile(emailRegexString) base64Regex = regexp.MustCompile(base64RegexString) base64URLRegex = regexp.MustCompile(base64URLRegexString) iSBN10Regex = regexp.MustCompile(iSBN10RegexString) iSBN13Regex = regexp.MustCompile(iSBN13RegexString) uUID3Regex = regexp.MustCompile(uUID3RegexString) uUID4Regex = regexp.MustCompile(uUID4RegexString) uUID5Regex = regexp.MustCompile(uUID5RegexString) uUIDRegex = regexp.MustCompile(uUIDRegexString) uUID3RFC4122Regex = regexp.MustCompile(uUID3RFC4122RegexString) uUID4RFC4122Regex = regexp.MustCompile(uUID4RFC4122RegexString) uUID5RFC4122Regex = regexp.MustCompile(uUID5RFC4122RegexString) uUIDRFC4122Regex = regexp.MustCompile(uUIDRFC4122RegexString) aSCIIRegex = regexp.MustCompile(aSCIIRegexString) printableASCIIRegex = regexp.MustCompile(printableASCIIRegexString) multibyteRegex = regexp.MustCompile(multibyteRegexString) dataURIRegex = regexp.MustCompile(dataURIRegexString) latitudeRegex = regexp.MustCompile(latitudeRegexString) longitudeRegex = regexp.MustCompile(longitudeRegexString) sSNRegex = regexp.MustCompile(sSNRegexString) hostnameRegexRFC952 = regexp.MustCompile(hostnameRegexStringRFC952) hostnameRegexRFC1123 = regexp.MustCompile(hostnameRegexStringRFC1123) fqdnRegexRFC1123 = regexp.MustCompile(fqdnRegexStringRFC1123) btcAddressRegex = regexp.MustCompile(btcAddressRegexString) btcUpperAddressRegexBech32 = regexp.MustCompile(btcAddressUpperRegexStringBech32) btcLowerAddressRegexBech32 = regexp.MustCompile(btcAddressLowerRegexStringBech32) ethAddressRegex = regexp.MustCompile(ethAddressRegexString) ethaddressRegexUpper = regexp.MustCompile(ethAddressUpperRegexString) ethAddressRegexLower = regexp.MustCompile(ethAddressLowerRegexString) uRLEncodedRegex = regexp.MustCompile(uRLEncodedRegexString) hTMLEncodedRegex = regexp.MustCompile(hTMLEncodedRegexString) hTMLRegex = regexp.MustCompile(hTMLRegexString) splitParamsRegex = regexp.MustCompile(splitParamsRegexString) ) validator-10.4.1/struct_level.go000066400000000000000000000124321374261122600166320ustar00rootroot00000000000000package validator import ( "context" "reflect" ) // StructLevelFunc accepts all values needed for struct level validation type StructLevelFunc func(sl StructLevel) // StructLevelFuncCtx accepts all values needed for struct level validation // but also allows passing of contextual validation information via context.Context. type StructLevelFuncCtx func(ctx context.Context, sl StructLevel) // wrapStructLevelFunc wraps normal StructLevelFunc makes it compatible with StructLevelFuncCtx func wrapStructLevelFunc(fn StructLevelFunc) StructLevelFuncCtx { return func(ctx context.Context, sl StructLevel) { fn(sl) } } // StructLevel contains all the information and helper functions // to validate a struct type StructLevel interface { // returns the main validation object, in case one wants to call validations internally. // this is so you don't have to use anonymous functions to get access to the validate // instance. Validator() *Validate // returns the top level struct, if any Top() reflect.Value // returns the current fields parent struct, if any Parent() reflect.Value // returns the current struct. Current() reflect.Value // ExtractType gets the actual underlying type of field value. // It will dive into pointers, customTypes and return you the // underlying value and its kind. ExtractType(field reflect.Value) (value reflect.Value, kind reflect.Kind, nullable bool) // reports an error just by passing the field and tag information // // NOTES: // // fieldName and altName get appended to the existing namespace that // validator is on. e.g. pass 'FirstName' or 'Names[0]' depending // on the nesting // // tag can be an existing validation tag or just something you make up // and process on the flip side it's up to you. ReportError(field interface{}, fieldName, structFieldName string, tag, param string) // reports an error just by passing ValidationErrors // // NOTES: // // relativeNamespace and relativeActualNamespace get appended to the // existing namespace that validator is on. // e.g. pass 'User.FirstName' or 'Users[0].FirstName' depending // on the nesting. most of the time they will be blank, unless you validate // at a level lower the the current field depth ReportValidationErrors(relativeNamespace, relativeActualNamespace string, errs ValidationErrors) } var _ StructLevel = new(validate) // Top returns the top level struct // // NOTE: this can be the same as the current struct being validated // if not is a nested struct. // // this is only called when within Struct and Field Level validation and // should not be relied upon for an acurate value otherwise. func (v *validate) Top() reflect.Value { return v.top } // Parent returns the current structs parent // // NOTE: this can be the same as the current struct being validated // if not is a nested struct. // // this is only called when within Struct and Field Level validation and // should not be relied upon for an acurate value otherwise. func (v *validate) Parent() reflect.Value { return v.slflParent } // Current returns the current struct. func (v *validate) Current() reflect.Value { return v.slCurrent } // Validator returns the main validation object, in case one want to call validations internally. func (v *validate) Validator() *Validate { return v.v } // ExtractType gets the actual underlying type of field value. func (v *validate) ExtractType(field reflect.Value) (reflect.Value, reflect.Kind, bool) { return v.extractTypeInternal(field, false) } // ReportError reports an error just by passing the field and tag information func (v *validate) ReportError(field interface{}, fieldName, structFieldName, tag, param string) { fv, kind, _ := v.extractTypeInternal(reflect.ValueOf(field), false) if len(structFieldName) == 0 { structFieldName = fieldName } v.str1 = string(append(v.ns, fieldName...)) if v.v.hasTagNameFunc || fieldName != structFieldName { v.str2 = string(append(v.actualNs, structFieldName...)) } else { v.str2 = v.str1 } if kind == reflect.Invalid { v.errs = append(v.errs, &fieldError{ v: v.v, tag: tag, actualTag: tag, ns: v.str1, structNs: v.str2, fieldLen: uint8(len(fieldName)), structfieldLen: uint8(len(structFieldName)), param: param, kind: kind, }, ) return } v.errs = append(v.errs, &fieldError{ v: v.v, tag: tag, actualTag: tag, ns: v.str1, structNs: v.str2, fieldLen: uint8(len(fieldName)), structfieldLen: uint8(len(structFieldName)), value: fv.Interface(), param: param, kind: kind, typ: fv.Type(), }, ) } // ReportValidationErrors reports ValidationErrors obtained from running validations within the Struct Level validation. // // NOTE: this function prepends the current namespace to the relative ones. func (v *validate) ReportValidationErrors(relativeNamespace, relativeStructNamespace string, errs ValidationErrors) { var err *fieldError for i := 0; i < len(errs); i++ { err = errs[i].(*fieldError) err.ns = string(append(append(v.ns, relativeNamespace...), err.ns...)) err.structNs = string(append(append(v.actualNs, relativeStructNamespace...), err.structNs...)) v.errs = append(v.errs, err) } } validator-10.4.1/testdata/000077500000000000000000000000001374261122600153775ustar00rootroot00000000000000validator-10.4.1/testdata/a.go000066400000000000000000000000211374261122600161370ustar00rootroot00000000000000package testdata validator-10.4.1/translations.go000066400000000000000000000006511374261122600166400ustar00rootroot00000000000000package validator import ut "github.com/go-playground/universal-translator" // TranslationFunc is the function type used to register or override // custom translations type TranslationFunc func(ut ut.Translator, fe FieldError) string // RegisterTranslationsFunc allows for registering of translations // for a 'ut.Translator' for use within the 'TranslationFunc' type RegisterTranslationsFunc func(ut ut.Translator) error validator-10.4.1/translations/000077500000000000000000000000001374261122600163075ustar00rootroot00000000000000validator-10.4.1/translations/en/000077500000000000000000000000001374261122600167115ustar00rootroot00000000000000validator-10.4.1/translations/en/en.go000066400000000000000000001001071374261122600176410ustar00rootroot00000000000000package en import ( "fmt" "log" "reflect" "strconv" "strings" "time" "github.com/go-playground/locales" ut "github.com/go-playground/universal-translator" "github.com/go-playground/validator/v10" ) // RegisterDefaultTranslations registers a set of default translations // for all built in tag's in validator; you may add your own as desired. func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (err error) { translations := []struct { tag string translation string override bool customRegisFunc validator.RegisterTranslationsFunc customTransFunc validator.TranslationFunc }{ { tag: "required", translation: "{0} is a required field", override: false, }, { tag: "len", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("len-string", "{0} must be {1} in length", false); err != nil { return } if err = ut.AddCardinal("len-string-character", "{0} character", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("len-string-character", "{0} characters", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("len-number", "{0} must be equal to {1}", false); err != nil { return } if err = ut.Add("len-items", "{0} must contain {1}", false); err != nil { return } if err = ut.AddCardinal("len-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("len-items-item", "{0} items", locales.PluralRuleOther, false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var digits uint64 var kind reflect.Kind if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { goto END } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string c, err = ut.C("len-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("len-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string c, err = ut.C("len-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("len-items", fe.Field(), c) default: t, err = ut.T("len-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "min", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("min-string", "{0} must be at least {1} in length", false); err != nil { return } if err = ut.AddCardinal("min-string-character", "{0} character", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("min-string-character", "{0} characters", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("min-number", "{0} must be {1} or greater", false); err != nil { return } if err = ut.Add("min-items", "{0} must contain at least {1}", false); err != nil { return } if err = ut.AddCardinal("min-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("min-items-item", "{0} items", locales.PluralRuleOther, false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var digits uint64 var kind reflect.Kind if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { goto END } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string c, err = ut.C("min-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("min-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string c, err = ut.C("min-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("min-items", fe.Field(), c) default: t, err = ut.T("min-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "max", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("max-string", "{0} must be a maximum of {1} in length", false); err != nil { return } if err = ut.AddCardinal("max-string-character", "{0} character", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("max-string-character", "{0} characters", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("max-number", "{0} must be {1} or less", false); err != nil { return } if err = ut.Add("max-items", "{0} must contain at maximum {1}", false); err != nil { return } if err = ut.AddCardinal("max-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("max-items-item", "{0} items", locales.PluralRuleOther, false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var digits uint64 var kind reflect.Kind if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { goto END } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string c, err = ut.C("max-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("max-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string c, err = ut.C("max-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("max-items", fe.Field(), c) default: t, err = ut.T("max-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "eq", translation: "{0} is not equal to {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { fmt.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ne", translation: "{0} should not be equal to {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { fmt.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "lt", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("lt-string", "{0} must be less than {1} in length", false); err != nil { return } if err = ut.AddCardinal("lt-string-character", "{0} character", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("lt-string-character", "{0} characters", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lt-number", "{0} must be less than {1}", false); err != nil { return } if err = ut.Add("lt-items", "{0} must contain less than {1}", false); err != nil { return } if err = ut.AddCardinal("lt-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("lt-items-item", "{0} items", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lt-datetime", "{0} must be less than the current Date & Time", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("lt-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lt-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("lt-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lt-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) goto END } t, err = ut.T("lt-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("lt-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "lte", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("lte-string", "{0} must be at maximum {1} in length", false); err != nil { return } if err = ut.AddCardinal("lte-string-character", "{0} character", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("lte-string-character", "{0} characters", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lte-number", "{0} must be {1} or less", false); err != nil { return } if err = ut.Add("lte-items", "{0} must contain at maximum {1}", false); err != nil { return } if err = ut.AddCardinal("lte-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("lte-items-item", "{0} items", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lte-datetime", "{0} must be less than or equal to the current Date & Time", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("lte-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lte-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("lte-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lte-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) goto END } t, err = ut.T("lte-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("lte-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "gt", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("gt-string", "{0} must be greater than {1} in length", false); err != nil { return } if err = ut.AddCardinal("gt-string-character", "{0} character", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("gt-string-character", "{0} characters", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gt-number", "{0} must be greater than {1}", false); err != nil { return } if err = ut.Add("gt-items", "{0} must contain more than {1}", false); err != nil { return } if err = ut.AddCardinal("gt-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("gt-items-item", "{0} items", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gt-datetime", "{0} must be greater than the current Date & Time", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("gt-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gt-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("gt-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gt-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) goto END } t, err = ut.T("gt-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("gt-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "gte", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("gte-string", "{0} must be at least {1} in length", false); err != nil { return } if err = ut.AddCardinal("gte-string-character", "{0} character", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("gte-string-character", "{0} characters", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gte-number", "{0} must be {1} or greater", false); err != nil { return } if err = ut.Add("gte-items", "{0} must contain at least {1}", false); err != nil { return } if err = ut.AddCardinal("gte-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("gte-items-item", "{0} items", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gte-datetime", "{0} must be greater than or equal to the current Date & Time", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("gte-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gte-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("gte-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gte-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) goto END } t, err = ut.T("gte-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("gte-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "eqfield", translation: "{0} must be equal to {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "eqcsfield", translation: "{0} must be equal to {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "necsfield", translation: "{0} cannot be equal to {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtcsfield", translation: "{0} must be greater than {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtecsfield", translation: "{0} must be greater than or equal to {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltcsfield", translation: "{0} must be less than {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltecsfield", translation: "{0} must be less than or equal to {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "nefield", translation: "{0} cannot be equal to {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtfield", translation: "{0} must be greater than {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtefield", translation: "{0} must be greater than or equal to {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltfield", translation: "{0} must be less than {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltefield", translation: "{0} must be less than or equal to {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "alpha", translation: "{0} can only contain alphabetic characters", override: false, }, { tag: "alphanum", translation: "{0} can only contain alphanumeric characters", override: false, }, { tag: "numeric", translation: "{0} must be a valid numeric value", override: false, }, { tag: "number", translation: "{0} must be a valid number", override: false, }, { tag: "hexadecimal", translation: "{0} must be a valid hexadecimal", override: false, }, { tag: "hexcolor", translation: "{0} must be a valid HEX color", override: false, }, { tag: "rgb", translation: "{0} must be a valid RGB color", override: false, }, { tag: "rgba", translation: "{0} must be a valid RGBA color", override: false, }, { tag: "hsl", translation: "{0} must be a valid HSL color", override: false, }, { tag: "hsla", translation: "{0} must be a valid HSLA color", override: false, }, { tag: "e164", translation: "{0} must be a valid E.164 formatted phone number", override: false, }, { tag: "email", translation: "{0} must be a valid email address", override: false, }, { tag: "url", translation: "{0} must be a valid URL", override: false, }, { tag: "uri", translation: "{0} must be a valid URI", override: false, }, { tag: "base64", translation: "{0} must be a valid Base64 string", override: false, }, { tag: "contains", translation: "{0} must contain the text '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "containsany", translation: "{0} must contain at least one of the following characters '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "excludes", translation: "{0} cannot contain the text '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "excludesall", translation: "{0} cannot contain any of the following characters '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "excludesrune", translation: "{0} cannot contain the following '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "isbn", translation: "{0} must be a valid ISBN number", override: false, }, { tag: "isbn10", translation: "{0} must be a valid ISBN-10 number", override: false, }, { tag: "isbn13", translation: "{0} must be a valid ISBN-13 number", override: false, }, { tag: "uuid", translation: "{0} must be a valid UUID", override: false, }, { tag: "uuid3", translation: "{0} must be a valid version 3 UUID", override: false, }, { tag: "uuid4", translation: "{0} must be a valid version 4 UUID", override: false, }, { tag: "uuid5", translation: "{0} must be a valid version 5 UUID", override: false, }, { tag: "ascii", translation: "{0} must contain only ascii characters", override: false, }, { tag: "printascii", translation: "{0} must contain only printable ascii characters", override: false, }, { tag: "multibyte", translation: "{0} must contain multibyte characters", override: false, }, { tag: "datauri", translation: "{0} must contain a valid Data URI", override: false, }, { tag: "latitude", translation: "{0} must contain valid latitude coordinates", override: false, }, { tag: "longitude", translation: "{0} must contain a valid longitude coordinates", override: false, }, { tag: "ssn", translation: "{0} must be a valid SSN number", override: false, }, { tag: "ipv4", translation: "{0} must be a valid IPv4 address", override: false, }, { tag: "ipv6", translation: "{0} must be a valid IPv6 address", override: false, }, { tag: "ip", translation: "{0} must be a valid IP address", override: false, }, { tag: "cidr", translation: "{0} must contain a valid CIDR notation", override: false, }, { tag: "cidrv4", translation: "{0} must contain a valid CIDR notation for an IPv4 address", override: false, }, { tag: "cidrv6", translation: "{0} must contain a valid CIDR notation for an IPv6 address", override: false, }, { tag: "tcp_addr", translation: "{0} must be a valid TCP address", override: false, }, { tag: "tcp4_addr", translation: "{0} must be a valid IPv4 TCP address", override: false, }, { tag: "tcp6_addr", translation: "{0} must be a valid IPv6 TCP address", override: false, }, { tag: "udp_addr", translation: "{0} must be a valid UDP address", override: false, }, { tag: "udp4_addr", translation: "{0} must be a valid IPv4 UDP address", override: false, }, { tag: "udp6_addr", translation: "{0} must be a valid IPv6 UDP address", override: false, }, { tag: "ip_addr", translation: "{0} must be a resolvable IP address", override: false, }, { tag: "ip4_addr", translation: "{0} must be a resolvable IPv4 address", override: false, }, { tag: "ip6_addr", translation: "{0} must be a resolvable IPv6 address", override: false, }, { tag: "unix_addr", translation: "{0} must be a resolvable UNIX address", override: false, }, { tag: "mac", translation: "{0} must contain a valid MAC address", override: false, }, { tag: "unique", translation: "{0} must contain unique values", override: false, }, { tag: "iscolor", translation: "{0} must be a valid color", override: false, }, { tag: "oneof", translation: "{0} must be one of [{1}]", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { s, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return s }, }, { tag: "json", translation: "{0} must be a valid json string", override: false, }, { tag: "lowercase", translation: "{0} must be a lowercase string", override: false, }, { tag: "uppercase", translation: "{0} must be an uppercase string", override: false, }, { tag: "datetime", translation: "{0} does not match the {1} format", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, } for _, t := range translations { if t.customTransFunc != nil && t.customRegisFunc != nil { err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, t.customTransFunc) } else if t.customTransFunc != nil && t.customRegisFunc == nil { err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), t.customTransFunc) } else if t.customTransFunc == nil && t.customRegisFunc != nil { err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, translateFunc) } else { err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), translateFunc) } if err != nil { return } } return } func registrationFunc(tag string, translation string, override bool) validator.RegisterTranslationsFunc { return func(ut ut.Translator) (err error) { if err = ut.Add(tag, translation, override); err != nil { return } return } } func translateFunc(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t } validator-10.4.1/translations/en/en_test.go000066400000000000000000000476751374261122600207240ustar00rootroot00000000000000package en import ( "testing" "time" . "github.com/go-playground/assert/v2" english "github.com/go-playground/locales/en" ut "github.com/go-playground/universal-translator" "github.com/go-playground/validator/v10" ) func TestTranslations(t *testing.T) { eng := english.New() uni := ut.New(eng, eng) trans, _ := uni.GetTranslator("en") validate := validator.New() err := RegisterDefaultTranslations(validate, trans) Equal(t, err, nil) type Inner struct { EqCSFieldString string NeCSFieldString string GtCSFieldString string GteCSFieldString string LtCSFieldString string LteCSFieldString string } type Test struct { Inner Inner RequiredString string `validate:"required"` RequiredNumber int `validate:"required"` RequiredMultiple []string `validate:"required"` LenString string `validate:"len=1"` LenNumber float64 `validate:"len=1113.00"` LenMultiple []string `validate:"len=7"` MinString string `validate:"min=1"` MinNumber float64 `validate:"min=1113.00"` MinMultiple []string `validate:"min=7"` MaxString string `validate:"max=3"` MaxNumber float64 `validate:"max=1113.00"` MaxMultiple []string `validate:"max=7"` EqString string `validate:"eq=3"` EqNumber float64 `validate:"eq=2.33"` EqMultiple []string `validate:"eq=7"` NeString string `validate:"ne="` NeNumber float64 `validate:"ne=0.00"` NeMultiple []string `validate:"ne=0"` LtString string `validate:"lt=3"` LtNumber float64 `validate:"lt=5.56"` LtMultiple []string `validate:"lt=2"` LtTime time.Time `validate:"lt"` LteString string `validate:"lte=3"` LteNumber float64 `validate:"lte=5.56"` LteMultiple []string `validate:"lte=2"` LteTime time.Time `validate:"lte"` GtString string `validate:"gt=3"` GtNumber float64 `validate:"gt=5.56"` GtMultiple []string `validate:"gt=2"` GtTime time.Time `validate:"gt"` GteString string `validate:"gte=3"` GteNumber float64 `validate:"gte=5.56"` GteMultiple []string `validate:"gte=2"` GteTime time.Time `validate:"gte"` EqFieldString string `validate:"eqfield=MaxString"` EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"` NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"` GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"` GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"` LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"` LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"` NeFieldString string `validate:"nefield=EqFieldString"` GtFieldString string `validate:"gtfield=MaxString"` GteFieldString string `validate:"gtefield=MaxString"` LtFieldString string `validate:"ltfield=MaxString"` LteFieldString string `validate:"ltefield=MaxString"` AlphaString string `validate:"alpha"` AlphanumString string `validate:"alphanum"` NumericString string `validate:"numeric"` NumberString string `validate:"number"` HexadecimalString string `validate:"hexadecimal"` HexColorString string `validate:"hexcolor"` RGBColorString string `validate:"rgb"` RGBAColorString string `validate:"rgba"` HSLColorString string `validate:"hsl"` HSLAColorString string `validate:"hsla"` Email string `validate:"email"` URL string `validate:"url"` URI string `validate:"uri"` Base64 string `validate:"base64"` Contains string `validate:"contains=purpose"` ContainsAny string `validate:"containsany=!@#$"` Excludes string `validate:"excludes=text"` ExcludesAll string `validate:"excludesall=!@#$"` ExcludesRune string `validate:"excludesrune=☻"` ISBN string `validate:"isbn"` ISBN10 string `validate:"isbn10"` ISBN13 string `validate:"isbn13"` UUID string `validate:"uuid"` UUID3 string `validate:"uuid3"` UUID4 string `validate:"uuid4"` UUID5 string `validate:"uuid5"` ASCII string `validate:"ascii"` PrintableASCII string `validate:"printascii"` MultiByte string `validate:"multibyte"` DataURI string `validate:"datauri"` Latitude string `validate:"latitude"` Longitude string `validate:"longitude"` SSN string `validate:"ssn"` IP string `validate:"ip"` IPv4 string `validate:"ipv4"` IPv6 string `validate:"ipv6"` CIDR string `validate:"cidr"` CIDRv4 string `validate:"cidrv4"` CIDRv6 string `validate:"cidrv6"` TCPAddr string `validate:"tcp_addr"` TCPAddrv4 string `validate:"tcp4_addr"` TCPAddrv6 string `validate:"tcp6_addr"` UDPAddr string `validate:"udp_addr"` UDPAddrv4 string `validate:"udp4_addr"` UDPAddrv6 string `validate:"udp6_addr"` IPAddr string `validate:"ip_addr"` IPAddrv4 string `validate:"ip4_addr"` IPAddrv6 string `validate:"ip6_addr"` UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future MAC string `validate:"mac"` IsColor string `validate:"iscolor"` StrPtrMinLen *string `validate:"min=10"` StrPtrMaxLen *string `validate:"max=1"` StrPtrLen *string `validate:"len=2"` StrPtrLt *string `validate:"lt=1"` StrPtrLte *string `validate:"lte=1"` StrPtrGt *string `validate:"gt=10"` StrPtrGte *string `validate:"gte=10"` OneOfString string `validate:"oneof=red green"` OneOfInt int `validate:"oneof=5 63"` UniqueSlice []string `validate:"unique"` UniqueArray [3]string `validate:"unique"` UniqueMap map[string]string `validate:"unique"` JSONString string `validate:"json"` LowercaseString string `validate:"lowercase"` UppercaseString string `validate:"uppercase"` Datetime string `validate:"datetime=2006-01-02"` } var test Test test.Inner.EqCSFieldString = "1234" test.Inner.GtCSFieldString = "1234" test.Inner.GteCSFieldString = "1234" test.MaxString = "1234" test.MaxNumber = 2000 test.MaxMultiple = make([]string, 9) test.LtString = "1234" test.LtNumber = 6 test.LtMultiple = make([]string, 3) test.LtTime = time.Now().Add(time.Hour * 24) test.LteString = "1234" test.LteNumber = 6 test.LteMultiple = make([]string, 3) test.LteTime = time.Now().Add(time.Hour * 24) test.LtFieldString = "12345" test.LteFieldString = "12345" test.LtCSFieldString = "1234" test.LteCSFieldString = "1234" test.AlphaString = "abc3" test.AlphanumString = "abc3!" test.NumericString = "12E.00" test.NumberString = "12E" test.Excludes = "this is some test text" test.ExcludesAll = "This is Great!" test.ExcludesRune = "Love it ☻" test.ASCII = "カタカナ" test.PrintableASCII = "カタカナ" test.MultiByte = "1234feerf" test.LowercaseString = "ABCDEFG" test.UppercaseString = "abcdefg" s := "toolong" test.StrPtrMaxLen = &s test.StrPtrLen = &s test.UniqueSlice = []string{"1234", "1234"} test.UniqueMap = map[string]string{"key1": "1234", "key2": "1234"} test.Datetime = "2008-Feb-01" err = validate.Struct(test) NotEqual(t, err, nil) errs, ok := err.(validator.ValidationErrors) Equal(t, ok, true) tests := []struct { ns string expected string }{ { ns: "Test.IsColor", expected: "IsColor must be a valid color", }, { ns: "Test.MAC", expected: "MAC must contain a valid MAC address", }, { ns: "Test.IPAddr", expected: "IPAddr must be a resolvable IP address", }, { ns: "Test.IPAddrv4", expected: "IPAddrv4 must be a resolvable IPv4 address", }, { ns: "Test.IPAddrv6", expected: "IPAddrv6 must be a resolvable IPv6 address", }, { ns: "Test.UDPAddr", expected: "UDPAddr must be a valid UDP address", }, { ns: "Test.UDPAddrv4", expected: "UDPAddrv4 must be a valid IPv4 UDP address", }, { ns: "Test.UDPAddrv6", expected: "UDPAddrv6 must be a valid IPv6 UDP address", }, { ns: "Test.TCPAddr", expected: "TCPAddr must be a valid TCP address", }, { ns: "Test.TCPAddrv4", expected: "TCPAddrv4 must be a valid IPv4 TCP address", }, { ns: "Test.TCPAddrv6", expected: "TCPAddrv6 must be a valid IPv6 TCP address", }, { ns: "Test.CIDR", expected: "CIDR must contain a valid CIDR notation", }, { ns: "Test.CIDRv4", expected: "CIDRv4 must contain a valid CIDR notation for an IPv4 address", }, { ns: "Test.CIDRv6", expected: "CIDRv6 must contain a valid CIDR notation for an IPv6 address", }, { ns: "Test.SSN", expected: "SSN must be a valid SSN number", }, { ns: "Test.IP", expected: "IP must be a valid IP address", }, { ns: "Test.IPv4", expected: "IPv4 must be a valid IPv4 address", }, { ns: "Test.IPv6", expected: "IPv6 must be a valid IPv6 address", }, { ns: "Test.DataURI", expected: "DataURI must contain a valid Data URI", }, { ns: "Test.Latitude", expected: "Latitude must contain valid latitude coordinates", }, { ns: "Test.Longitude", expected: "Longitude must contain a valid longitude coordinates", }, { ns: "Test.MultiByte", expected: "MultiByte must contain multibyte characters", }, { ns: "Test.ASCII", expected: "ASCII must contain only ascii characters", }, { ns: "Test.PrintableASCII", expected: "PrintableASCII must contain only printable ascii characters", }, { ns: "Test.UUID", expected: "UUID must be a valid UUID", }, { ns: "Test.UUID3", expected: "UUID3 must be a valid version 3 UUID", }, { ns: "Test.UUID4", expected: "UUID4 must be a valid version 4 UUID", }, { ns: "Test.UUID5", expected: "UUID5 must be a valid version 5 UUID", }, { ns: "Test.ISBN", expected: "ISBN must be a valid ISBN number", }, { ns: "Test.ISBN10", expected: "ISBN10 must be a valid ISBN-10 number", }, { ns: "Test.ISBN13", expected: "ISBN13 must be a valid ISBN-13 number", }, { ns: "Test.Excludes", expected: "Excludes cannot contain the text 'text'", }, { ns: "Test.ExcludesAll", expected: "ExcludesAll cannot contain any of the following characters '!@#$'", }, { ns: "Test.ExcludesRune", expected: "ExcludesRune cannot contain the following '☻'", }, { ns: "Test.ContainsAny", expected: "ContainsAny must contain at least one of the following characters '!@#$'", }, { ns: "Test.Contains", expected: "Contains must contain the text 'purpose'", }, { ns: "Test.Base64", expected: "Base64 must be a valid Base64 string", }, { ns: "Test.Email", expected: "Email must be a valid email address", }, { ns: "Test.URL", expected: "URL must be a valid URL", }, { ns: "Test.URI", expected: "URI must be a valid URI", }, { ns: "Test.RGBColorString", expected: "RGBColorString must be a valid RGB color", }, { ns: "Test.RGBAColorString", expected: "RGBAColorString must be a valid RGBA color", }, { ns: "Test.HSLColorString", expected: "HSLColorString must be a valid HSL color", }, { ns: "Test.HSLAColorString", expected: "HSLAColorString must be a valid HSLA color", }, { ns: "Test.HexadecimalString", expected: "HexadecimalString must be a valid hexadecimal", }, { ns: "Test.HexColorString", expected: "HexColorString must be a valid HEX color", }, { ns: "Test.NumberString", expected: "NumberString must be a valid number", }, { ns: "Test.NumericString", expected: "NumericString must be a valid numeric value", }, { ns: "Test.AlphanumString", expected: "AlphanumString can only contain alphanumeric characters", }, { ns: "Test.AlphaString", expected: "AlphaString can only contain alphabetic characters", }, { ns: "Test.LtFieldString", expected: "LtFieldString must be less than MaxString", }, { ns: "Test.LteFieldString", expected: "LteFieldString must be less than or equal to MaxString", }, { ns: "Test.GtFieldString", expected: "GtFieldString must be greater than MaxString", }, { ns: "Test.GteFieldString", expected: "GteFieldString must be greater than or equal to MaxString", }, { ns: "Test.NeFieldString", expected: "NeFieldString cannot be equal to EqFieldString", }, { ns: "Test.LtCSFieldString", expected: "LtCSFieldString must be less than Inner.LtCSFieldString", }, { ns: "Test.LteCSFieldString", expected: "LteCSFieldString must be less than or equal to Inner.LteCSFieldString", }, { ns: "Test.GtCSFieldString", expected: "GtCSFieldString must be greater than Inner.GtCSFieldString", }, { ns: "Test.GteCSFieldString", expected: "GteCSFieldString must be greater than or equal to Inner.GteCSFieldString", }, { ns: "Test.NeCSFieldString", expected: "NeCSFieldString cannot be equal to Inner.NeCSFieldString", }, { ns: "Test.EqCSFieldString", expected: "EqCSFieldString must be equal to Inner.EqCSFieldString", }, { ns: "Test.EqFieldString", expected: "EqFieldString must be equal to MaxString", }, { ns: "Test.GteString", expected: "GteString must be at least 3 characters in length", }, { ns: "Test.GteNumber", expected: "GteNumber must be 5.56 or greater", }, { ns: "Test.GteMultiple", expected: "GteMultiple must contain at least 2 items", }, { ns: "Test.GteTime", expected: "GteTime must be greater than or equal to the current Date & Time", }, { ns: "Test.GtString", expected: "GtString must be greater than 3 characters in length", }, { ns: "Test.GtNumber", expected: "GtNumber must be greater than 5.56", }, { ns: "Test.GtMultiple", expected: "GtMultiple must contain more than 2 items", }, { ns: "Test.GtTime", expected: "GtTime must be greater than the current Date & Time", }, { ns: "Test.LteString", expected: "LteString must be at maximum 3 characters in length", }, { ns: "Test.LteNumber", expected: "LteNumber must be 5.56 or less", }, { ns: "Test.LteMultiple", expected: "LteMultiple must contain at maximum 2 items", }, { ns: "Test.LteTime", expected: "LteTime must be less than or equal to the current Date & Time", }, { ns: "Test.LtString", expected: "LtString must be less than 3 characters in length", }, { ns: "Test.LtNumber", expected: "LtNumber must be less than 5.56", }, { ns: "Test.LtMultiple", expected: "LtMultiple must contain less than 2 items", }, { ns: "Test.LtTime", expected: "LtTime must be less than the current Date & Time", }, { ns: "Test.NeString", expected: "NeString should not be equal to ", }, { ns: "Test.NeNumber", expected: "NeNumber should not be equal to 0.00", }, { ns: "Test.NeMultiple", expected: "NeMultiple should not be equal to 0", }, { ns: "Test.EqString", expected: "EqString is not equal to 3", }, { ns: "Test.EqNumber", expected: "EqNumber is not equal to 2.33", }, { ns: "Test.EqMultiple", expected: "EqMultiple is not equal to 7", }, { ns: "Test.MaxString", expected: "MaxString must be a maximum of 3 characters in length", }, { ns: "Test.MaxNumber", expected: "MaxNumber must be 1,113.00 or less", }, { ns: "Test.MaxMultiple", expected: "MaxMultiple must contain at maximum 7 items", }, { ns: "Test.MinString", expected: "MinString must be at least 1 character in length", }, { ns: "Test.MinNumber", expected: "MinNumber must be 1,113.00 or greater", }, { ns: "Test.MinMultiple", expected: "MinMultiple must contain at least 7 items", }, { ns: "Test.LenString", expected: "LenString must be 1 character in length", }, { ns: "Test.LenNumber", expected: "LenNumber must be equal to 1,113.00", }, { ns: "Test.LenMultiple", expected: "LenMultiple must contain 7 items", }, { ns: "Test.RequiredString", expected: "RequiredString is a required field", }, { ns: "Test.RequiredNumber", expected: "RequiredNumber is a required field", }, { ns: "Test.RequiredMultiple", expected: "RequiredMultiple is a required field", }, { ns: "Test.StrPtrMinLen", expected: "StrPtrMinLen must be at least 10 characters in length", }, { ns: "Test.StrPtrMaxLen", expected: "StrPtrMaxLen must be a maximum of 1 character in length", }, { ns: "Test.StrPtrLen", expected: "StrPtrLen must be 2 characters in length", }, { ns: "Test.StrPtrLt", expected: "StrPtrLt must be less than 1 character in length", }, { ns: "Test.StrPtrLte", expected: "StrPtrLte must be at maximum 1 character in length", }, { ns: "Test.StrPtrGt", expected: "StrPtrGt must be greater than 10 characters in length", }, { ns: "Test.StrPtrGte", expected: "StrPtrGte must be at least 10 characters in length", }, { ns: "Test.OneOfString", expected: "OneOfString must be one of [red green]", }, { ns: "Test.OneOfInt", expected: "OneOfInt must be one of [5 63]", }, { ns: "Test.UniqueSlice", expected: "UniqueSlice must contain unique values", }, { ns: "Test.UniqueArray", expected: "UniqueArray must contain unique values", }, { ns: "Test.UniqueMap", expected: "UniqueMap must contain unique values", }, { ns: "Test.JSONString", expected: "JSONString must be a valid json string", }, { ns: "Test.LowercaseString", expected: "LowercaseString must be a lowercase string", }, { ns: "Test.UppercaseString", expected: "UppercaseString must be an uppercase string", }, { ns: "Test.Datetime", expected: "Datetime does not match the 2006-01-02 format", }, } for _, tt := range tests { var fe validator.FieldError for _, e := range errs { if tt.ns == e.Namespace() { fe = e break } } NotEqual(t, fe, nil) Equal(t, tt.expected, fe.Translate(trans)) } } validator-10.4.1/translations/es/000077500000000000000000000000001374261122600167165ustar00rootroot00000000000000validator-10.4.1/translations/es/es.go000066400000000000000000000773751374261122600176770ustar00rootroot00000000000000package es import ( "fmt" "log" "reflect" "strconv" "strings" "time" "github.com/go-playground/locales" ut "github.com/go-playground/universal-translator" "github.com/go-playground/validator/v10" ) // RegisterDefaultTranslations registers a set of default translations // for all built in tag's in validator; you may add your own as desired. func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (err error) { translations := []struct { tag string translation string override bool customRegisFunc validator.RegisterTranslationsFunc customTransFunc validator.TranslationFunc }{ { tag: "required", translation: "{0} es un campo requerido", override: false, }, { tag: "len", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("len-string", "{0} debe tener {1} de longitud", false); err != nil { return } if err = ut.AddCardinal("len-string-character", "{0} carácter", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("len-string-character", "{0} caracteres", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("len-number", "{0} debe ser igual a {1}", false); err != nil { return } if err = ut.Add("len-items", "{0} debe contener {1}", false); err != nil { return } if err = ut.AddCardinal("len-items-item", "{0} elemento", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("len-items-item", "{0} elementos", locales.PluralRuleOther, false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var digits uint64 var kind reflect.Kind if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { goto END } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string c, err = ut.C("len-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("len-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string c, err = ut.C("len-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("len-items", fe.Field(), c) default: t, err = ut.T("len-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "min", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("min-string", "{0} debe tener al menos {1} de longitud", false); err != nil { return } if err = ut.AddCardinal("min-string-character", "{0} carácter", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("min-string-character", "{0} caracteres", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("min-number", "{0} debe ser {1} o más", false); err != nil { return } if err = ut.Add("min-items", "{0} debe contener al menos {1}", false); err != nil { return } if err = ut.AddCardinal("min-items-item", "{0} elemento", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("min-items-item", "{0} elementos", locales.PluralRuleOther, false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var digits uint64 var kind reflect.Kind if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { goto END } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string c, err = ut.C("min-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("min-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string c, err = ut.C("min-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("min-items", fe.Field(), c) default: t, err = ut.T("min-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "max", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("max-string", "{0} debe tener un máximo de {1} de longitud", false); err != nil { return } if err = ut.AddCardinal("max-string-character", "{0} carácter", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("max-string-character", "{0} caracteres", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("max-number", "{0} debe ser {1} o menos", false); err != nil { return } if err = ut.Add("max-items", "{0} debe contener como máximo {1}", false); err != nil { return } if err = ut.AddCardinal("max-items-item", "{0} elemento", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("max-items-item", "{0} elementos", locales.PluralRuleOther, false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var digits uint64 var kind reflect.Kind if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { goto END } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string c, err = ut.C("max-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("max-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string c, err = ut.C("max-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("max-items", fe.Field(), c) default: t, err = ut.T("max-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "eq", translation: "{0} no es igual a {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { fmt.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ne", translation: "{0} no debería ser igual a {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { fmt.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "lt", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("lt-string", "{0} debe tener menos de {1} de longitud", false); err != nil { return } if err = ut.AddCardinal("lt-string-character", "{0} carácter", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("lt-string-character", "{0} caracteres", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lt-number", "{0} debe ser menos de {1}", false); err != nil { return } if err = ut.Add("lt-items", "{0} debe contener menos de {1}", false); err != nil { return } if err = ut.AddCardinal("lt-items-item", "{0} elemento", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("lt-items-item", "{0} elementos", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lt-datetime", "{0} debe ser antes de la fecha y hora actual", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("lt-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lt-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("lt-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lt-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) goto END } t, err = ut.T("lt-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("lt-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "lte", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("lte-string", "{0} debe tener un máximo de {1} de longitud", false); err != nil { return } if err = ut.AddCardinal("lte-string-character", "{0} carácter", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("lte-string-character", "{0} caracteres", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lte-number", "{0} debe ser {1} o menos", false); err != nil { return } if err = ut.Add("lte-items", "{0} debe contener como máximo {1}", false); err != nil { return } if err = ut.AddCardinal("lte-items-item", "{0} elemento", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("lte-items-item", "{0} elementos", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lte-datetime", "{0} debe ser antes o durante la fecha y hora actual", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("lte-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lte-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("lte-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lte-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) goto END } t, err = ut.T("lte-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("lte-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "gt", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("gt-string", "{0} debe ser mayor que {1} en longitud", false); err != nil { return } if err = ut.AddCardinal("gt-string-character", "{0} carácter", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("gt-string-character", "{0} caracteres", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gt-number", "{0} debe ser mayor que {1}", false); err != nil { return } if err = ut.Add("gt-items", "{0} debe contener más de {1}", false); err != nil { return } if err = ut.AddCardinal("gt-items-item", "{0} elemento", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("gt-items-item", "{0} elementos", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gt-datetime", "{0} debe ser después de la fecha y hora actual", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("gt-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gt-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("gt-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gt-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) goto END } t, err = ut.T("gt-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("gt-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "gte", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("gte-string", "{0} debe tener al menos {1} de longitud", false); err != nil { return } if err = ut.AddCardinal("gte-string-character", "{0} carácter", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("gte-string-character", "{0} caracteres", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gte-number", "{0} debe ser {1} o mayor", false); err != nil { return } if err = ut.Add("gte-items", "{0} debe contener al menos {1}", false); err != nil { return } if err = ut.AddCardinal("gte-items-item", "{0} elemento", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("gte-items-item", "{0} elementos", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gte-datetime", "{0} debe ser después o durante la fecha y hora actuales", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("gte-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gte-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("gte-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gte-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) goto END } t, err = ut.T("gte-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("gte-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "eqfield", translation: "{0} debe ser igual a {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "eqcsfield", translation: "{0} debe ser igual a {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "necsfield", translation: "{0} no puede ser igual a {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtcsfield", translation: "{0} debe ser mayor que {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtecsfield", translation: "{0} debe ser mayor o igual a {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltcsfield", translation: "{0} debe ser menor que {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltecsfield", translation: "{0} debe ser menor o igual a {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "nefield", translation: "{0} no puede ser igual a {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtfield", translation: "{0} debe ser mayor que {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtefield", translation: "{0} debe ser mayor o igual a {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltfield", translation: "{0} debe ser menor que {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltefield", translation: "{0} debe ser menor o igual a {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "alpha", translation: "{0} sólo puede contener caracteres alfabéticos", override: false, }, { tag: "alphanum", translation: "{0} sólo puede contener caracteres alfanuméricos", override: false, }, { tag: "numeric", translation: "{0} debe ser un valor numérico válido", override: false, }, { tag: "number", translation: "{0} debe ser un número válido", override: false, }, { tag: "hexadecimal", translation: "{0} debe ser un hexadecimal válido", override: false, }, { tag: "hexcolor", translation: "{0} debe ser un color HEX válido", override: false, }, { tag: "rgb", translation: "{0} debe ser un color RGB válido", override: false, }, { tag: "rgba", translation: "{0} debe ser un color RGBA válido", override: false, }, { tag: "hsl", translation: "{0} debe ser un color HSL válido", override: false, }, { tag: "hsla", translation: "{0} debe ser un color HSL válido", override: false, }, { tag: "e164", translation: "{0} debe ser un número de teléfono válido con formato E.164", override: false, }, { tag: "email", translation: "{0} debe ser una dirección de correo electrónico válida", override: false, }, { tag: "url", translation: "{0} debe ser un URL válido", override: false, }, { tag: "uri", translation: "{0} debe ser una URI válida", override: false, }, { tag: "base64", translation: "{0} debe ser una cadena de Base64 válida", override: false, }, { tag: "contains", translation: "{0} debe contener el texto '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "containsany", translation: "{0} debe contener al menos uno de los siguientes caracteres '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "excludes", translation: "{0} no puede contener el texto '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "excludesall", translation: "{0} no puede contener ninguno de los siguientes caracteres '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "excludesrune", translation: "{0} no puede contener lo siguiente '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "isbn", translation: "{0} debe ser un número ISBN válido", override: false, }, { tag: "isbn10", translation: "{0} debe ser un número ISBN-10 válido", override: false, }, { tag: "isbn13", translation: "{0} debe ser un número ISBN-13 válido", override: false, }, { tag: "uuid", translation: "{0} debe ser un UUID válido", override: false, }, { tag: "uuid3", translation: "{0} debe ser una versión válida 3 UUID", override: false, }, { tag: "uuid4", translation: "{0} debe ser una versión válida 4 UUID", override: false, }, { tag: "uuid5", translation: "{0} debe ser una versión válida 5 UUID", override: false, }, { tag: "ascii", translation: "{0} debe contener sólo caracteres ascii", override: false, }, { tag: "printascii", translation: "{0} debe contener sólo caracteres ASCII imprimibles", override: false, }, { tag: "multibyte", translation: "{0} debe contener caracteres multibyte", override: false, }, { tag: "datauri", translation: "{0} debe contener un URI de datos válido", override: false, }, { tag: "latitude", translation: "{0} debe contener coordenadas de latitud válidas", override: false, }, { tag: "longitude", translation: "{0} debe contener unas coordenadas de longitud válidas", override: false, }, { tag: "ssn", translation: "{0} debe ser un número válido de SSN", override: false, }, { tag: "ipv4", translation: "{0} debe ser una dirección IPv4 válida", override: false, }, { tag: "ipv6", translation: "{0} debe ser una dirección IPv6 válida", override: false, }, { tag: "ip", translation: "{0} debe ser una dirección IP válida", override: false, }, { tag: "cidr", translation: "{0} debe contener una anotación válida del CIDR", override: false, }, { tag: "cidrv4", translation: "{0} debe contener una notación CIDR válida para una dirección IPv4", override: false, }, { tag: "cidrv6", translation: "{0} debe contener una notación CIDR válida para una dirección IPv6", override: false, }, { tag: "tcp_addr", translation: "{0} debe ser una dirección TCP válida", override: false, }, { tag: "tcp4_addr", translation: "{0} debe ser una dirección IPv4 TCP válida", override: false, }, { tag: "tcp6_addr", translation: "{0} debe ser una dirección IPv6 TCP válida", override: false, }, { tag: "udp_addr", translation: "{0} debe ser una dirección UDP válida", override: false, }, { tag: "udp4_addr", translation: "{0} debe ser una dirección IPv4 UDP válida", override: false, }, { tag: "udp6_addr", translation: "{0} debe ser una dirección IPv6 UDP válida", override: false, }, { tag: "ip_addr", translation: "{0} debe ser una dirección IP resoluble", override: false, }, { tag: "ip4_addr", translation: "{0} debe ser una dirección IPv4 resoluble", override: false, }, { tag: "ip6_addr", translation: "{0} debe ser una dirección IPv6 resoluble", override: false, }, { tag: "unix_addr", translation: "{0} debe ser una dirección UNIX resoluble", override: false, }, { tag: "mac", translation: "{0} debe contener una dirección MAC válida", override: false, }, { tag: "unique", translation: "{0} debe contener valores únicos", override: false, }, { tag: "iscolor", translation: "{0} debe ser un color válido", override: false, }, { tag: "oneof", translation: "{0} debe ser uno de [{1}]", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { s, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return s }, }, } for _, t := range translations { if t.customTransFunc != nil && t.customRegisFunc != nil { err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, t.customTransFunc) } else if t.customTransFunc != nil && t.customRegisFunc == nil { err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), t.customTransFunc) } else if t.customTransFunc == nil && t.customRegisFunc != nil { err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, translateFunc) } else { err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), translateFunc) } if err != nil { return } } return } func registrationFunc(tag string, translation string, override bool) validator.RegisterTranslationsFunc { return func(ut ut.Translator) (err error) { if err = ut.Add(tag, translation, override); err != nil { return } return } } func translateFunc(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t } validator-10.4.1/translations/es/es_test.go000066400000000000000000000471121374261122600207200ustar00rootroot00000000000000package es import ( "testing" "time" spanish "github.com/go-playground/locales/es" ut "github.com/go-playground/universal-translator" . "github.com/go-playground/assert/v2" "github.com/go-playground/validator/v10" ) func TestTranslations(t *testing.T) { spa := spanish.New() uni := ut.New(spa, spa) trans, _ := uni.GetTranslator("es") validate := validator.New() err := RegisterDefaultTranslations(validate, trans) Equal(t, err, nil) type Inner struct { EqCSFieldString string NeCSFieldString string GtCSFieldString string GteCSFieldString string LtCSFieldString string LteCSFieldString string } type Test struct { Inner Inner RequiredString string `validate:"required"` RequiredNumber int `validate:"required"` RequiredMultiple []string `validate:"required"` LenString string `validate:"len=1"` LenNumber float64 `validate:"len=1113.00"` LenMultiple []string `validate:"len=7"` MinString string `validate:"min=1"` MinNumber float64 `validate:"min=1113.00"` MinMultiple []string `validate:"min=7"` MaxString string `validate:"max=3"` MaxNumber float64 `validate:"max=1113.00"` MaxMultiple []string `validate:"max=7"` EqString string `validate:"eq=3"` EqNumber float64 `validate:"eq=2.33"` EqMultiple []string `validate:"eq=7"` NeString string `validate:"ne="` NeNumber float64 `validate:"ne=0.00"` NeMultiple []string `validate:"ne=0"` LtString string `validate:"lt=3"` LtNumber float64 `validate:"lt=5.56"` LtMultiple []string `validate:"lt=2"` LtTime time.Time `validate:"lt"` LteString string `validate:"lte=3"` LteNumber float64 `validate:"lte=5.56"` LteMultiple []string `validate:"lte=2"` LteTime time.Time `validate:"lte"` GtString string `validate:"gt=3"` GtNumber float64 `validate:"gt=5.56"` GtMultiple []string `validate:"gt=2"` GtTime time.Time `validate:"gt"` GteString string `validate:"gte=3"` GteNumber float64 `validate:"gte=5.56"` GteMultiple []string `validate:"gte=2"` GteTime time.Time `validate:"gte"` EqFieldString string `validate:"eqfield=MaxString"` EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"` NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"` GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"` GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"` LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"` LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"` NeFieldString string `validate:"nefield=EqFieldString"` GtFieldString string `validate:"gtfield=MaxString"` GteFieldString string `validate:"gtefield=MaxString"` LtFieldString string `validate:"ltfield=MaxString"` LteFieldString string `validate:"ltefield=MaxString"` AlphaString string `validate:"alpha"` AlphanumString string `validate:"alphanum"` NumericString string `validate:"numeric"` NumberString string `validate:"number"` HexadecimalString string `validate:"hexadecimal"` HexColorString string `validate:"hexcolor"` RGBColorString string `validate:"rgb"` RGBAColorString string `validate:"rgba"` HSLColorString string `validate:"hsl"` HSLAColorString string `validate:"hsla"` Email string `validate:"email"` URL string `validate:"url"` URI string `validate:"uri"` Base64 string `validate:"base64"` Contains string `validate:"contains=purpose"` ContainsAny string `validate:"containsany=!@#$"` Excludes string `validate:"excludes=text"` ExcludesAll string `validate:"excludesall=!@#$"` ExcludesRune string `validate:"excludesrune=☻"` ISBN string `validate:"isbn"` ISBN10 string `validate:"isbn10"` ISBN13 string `validate:"isbn13"` UUID string `validate:"uuid"` UUID3 string `validate:"uuid3"` UUID4 string `validate:"uuid4"` UUID5 string `validate:"uuid5"` ASCII string `validate:"ascii"` PrintableASCII string `validate:"printascii"` MultiByte string `validate:"multibyte"` DataURI string `validate:"datauri"` Latitude string `validate:"latitude"` Longitude string `validate:"longitude"` SSN string `validate:"ssn"` IP string `validate:"ip"` IPv4 string `validate:"ipv4"` IPv6 string `validate:"ipv6"` CIDR string `validate:"cidr"` CIDRv4 string `validate:"cidrv4"` CIDRv6 string `validate:"cidrv6"` TCPAddr string `validate:"tcp_addr"` TCPAddrv4 string `validate:"tcp4_addr"` TCPAddrv6 string `validate:"tcp6_addr"` UDPAddr string `validate:"udp_addr"` UDPAddrv4 string `validate:"udp4_addr"` UDPAddrv6 string `validate:"udp6_addr"` IPAddr string `validate:"ip_addr"` IPAddrv4 string `validate:"ip4_addr"` IPAddrv6 string `validate:"ip6_addr"` UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future MAC string `validate:"mac"` IsColor string `validate:"iscolor"` StrPtrMinLen *string `validate:"min=10"` StrPtrMaxLen *string `validate:"max=1"` StrPtrLen *string `validate:"len=2"` StrPtrLt *string `validate:"lt=1"` StrPtrLte *string `validate:"lte=1"` StrPtrGt *string `validate:"gt=10"` StrPtrGte *string `validate:"gte=10"` OneOfString string `validate:"oneof=red green"` OneOfInt int `validate:"oneof=5 63"` UniqueSlice []string `validate:"unique"` UniqueArray [3]string `validate:"unique"` UniqueMap map[string]string `validate:"unique"` } var test Test test.Inner.EqCSFieldString = "1234" test.Inner.GtCSFieldString = "1234" test.Inner.GteCSFieldString = "1234" test.MaxString = "1234" test.MaxNumber = 2000 test.MaxMultiple = make([]string, 9) test.LtString = "1234" test.LtNumber = 6 test.LtMultiple = make([]string, 3) test.LtTime = time.Now().Add(time.Hour * 24) test.LteString = "1234" test.LteNumber = 6 test.LteMultiple = make([]string, 3) test.LteTime = time.Now().Add(time.Hour * 24) test.LtFieldString = "12345" test.LteFieldString = "12345" test.LtCSFieldString = "1234" test.LteCSFieldString = "1234" test.AlphaString = "abc3" test.AlphanumString = "abc3!" test.NumericString = "12E.00" test.NumberString = "12E" test.Excludes = "this is some test text" test.ExcludesAll = "This is Great!" test.ExcludesRune = "Love it ☻" test.ASCII = "カタカナ" test.PrintableASCII = "カタカナ" test.MultiByte = "1234feerf" s := "toolong" test.StrPtrMaxLen = &s test.StrPtrLen = &s test.UniqueSlice = []string{"1234", "1234"} test.UniqueMap = map[string]string{"key1": "1234", "key2": "1234"} err = validate.Struct(test) NotEqual(t, err, nil) errs, ok := err.(validator.ValidationErrors) Equal(t, ok, true) tests := []struct { ns string expected string }{ { ns: "Test.IsColor", expected: "IsColor debe ser un color válido", }, { ns: "Test.MAC", expected: "MAC debe contener una dirección MAC válida", }, { ns: "Test.IPAddr", expected: "IPAddr debe ser una dirección IP resoluble", }, { ns: "Test.IPAddrv4", expected: "IPAddrv4 debe ser una dirección IPv4 resoluble", }, { ns: "Test.IPAddrv6", expected: "IPAddrv6 debe ser una dirección IPv6 resoluble", }, { ns: "Test.UDPAddr", expected: "UDPAddr debe ser una dirección UDP válida", }, { ns: "Test.UDPAddrv4", expected: "UDPAddrv4 debe ser una dirección IPv4 UDP válida", }, { ns: "Test.UDPAddrv6", expected: "UDPAddrv6 debe ser una dirección IPv6 UDP válida", }, { ns: "Test.TCPAddr", expected: "TCPAddr debe ser una dirección TCP válida", }, { ns: "Test.TCPAddrv4", expected: "TCPAddrv4 debe ser una dirección IPv4 TCP válida", }, { ns: "Test.TCPAddrv6", expected: "TCPAddrv6 debe ser una dirección IPv6 TCP válida", }, { ns: "Test.CIDR", expected: "CIDR debe contener una anotación válida del CIDR", }, { ns: "Test.CIDRv4", expected: "CIDRv4 debe contener una notación CIDR válida para una dirección IPv4", }, { ns: "Test.CIDRv6", expected: "CIDRv6 debe contener una notación CIDR válida para una dirección IPv6", }, { ns: "Test.SSN", expected: "SSN debe ser un número válido de SSN", }, { ns: "Test.IP", expected: "IP debe ser una dirección IP válida", }, { ns: "Test.IPv4", expected: "IPv4 debe ser una dirección IPv4 válida", }, { ns: "Test.IPv6", expected: "IPv6 debe ser una dirección IPv6 válida", }, { ns: "Test.DataURI", expected: "DataURI debe contener un URI de datos válido", }, { ns: "Test.Latitude", expected: "Latitude debe contener coordenadas de latitud válidas", }, { ns: "Test.Longitude", expected: "Longitude debe contener unas coordenadas de longitud válidas", }, { ns: "Test.MultiByte", expected: "MultiByte debe contener caracteres multibyte", }, { ns: "Test.ASCII", expected: "ASCII debe contener sólo caracteres ascii", }, { ns: "Test.PrintableASCII", expected: "PrintableASCII debe contener sólo caracteres ASCII imprimibles", }, { ns: "Test.UUID", expected: "UUID debe ser un UUID válido", }, { ns: "Test.UUID3", expected: "UUID3 debe ser una versión válida 3 UUID", }, { ns: "Test.UUID4", expected: "UUID4 debe ser una versión válida 4 UUID", }, { ns: "Test.UUID5", expected: "UUID5 debe ser una versión válida 5 UUID", }, { ns: "Test.ISBN", expected: "ISBN debe ser un número ISBN válido", }, { ns: "Test.ISBN10", expected: "ISBN10 debe ser un número ISBN-10 válido", }, { ns: "Test.ISBN13", expected: "ISBN13 debe ser un número ISBN-13 válido", }, { ns: "Test.Excludes", expected: "Excludes no puede contener el texto 'text'", }, { ns: "Test.ExcludesAll", expected: "ExcludesAll no puede contener ninguno de los siguientes caracteres '!@#$'", }, { ns: "Test.ExcludesRune", expected: "ExcludesRune no puede contener lo siguiente '☻'", }, { ns: "Test.ContainsAny", expected: "ContainsAny debe contener al menos uno de los siguientes caracteres '!@#$'", }, { ns: "Test.Contains", expected: "Contains debe contener el texto 'purpose'", }, { ns: "Test.Base64", expected: "Base64 debe ser una cadena de Base64 válida", }, { ns: "Test.Email", expected: "Email debe ser una dirección de correo electrónico válida", }, { ns: "Test.URL", expected: "URL debe ser un URL válido", }, { ns: "Test.URI", expected: "URI debe ser una URI válida", }, { ns: "Test.RGBColorString", expected: "RGBColorString debe ser un color RGB válido", }, { ns: "Test.RGBAColorString", expected: "RGBAColorString debe ser un color RGBA válido", }, { ns: "Test.HSLColorString", expected: "HSLColorString debe ser un color HSL válido", }, { ns: "Test.HSLAColorString", expected: "HSLAColorString debe ser un color HSL válido", }, { ns: "Test.HexadecimalString", expected: "HexadecimalString debe ser un hexadecimal válido", }, { ns: "Test.HexColorString", expected: "HexColorString debe ser un color HEX válido", }, { ns: "Test.NumberString", expected: "NumberString debe ser un número válido", }, { ns: "Test.NumericString", expected: "NumericString debe ser un valor numérico válido", }, { ns: "Test.AlphanumString", expected: "AlphanumString sólo puede contener caracteres alfanuméricos", }, { ns: "Test.AlphaString", expected: "AlphaString sólo puede contener caracteres alfabéticos", }, { ns: "Test.LtFieldString", expected: "LtFieldString debe ser menor que MaxString", }, { ns: "Test.LteFieldString", expected: "LteFieldString debe ser menor o igual a MaxString", }, { ns: "Test.GtFieldString", expected: "GtFieldString debe ser mayor que MaxString", }, { ns: "Test.GteFieldString", expected: "GteFieldString debe ser mayor o igual a MaxString", }, { ns: "Test.NeFieldString", expected: "NeFieldString no puede ser igual a EqFieldString", }, { ns: "Test.LtCSFieldString", expected: "LtCSFieldString debe ser menor que Inner.LtCSFieldString", }, { ns: "Test.LteCSFieldString", expected: "LteCSFieldString debe ser menor o igual a Inner.LteCSFieldString", }, { ns: "Test.GtCSFieldString", expected: "GtCSFieldString debe ser mayor que Inner.GtCSFieldString", }, { ns: "Test.GteCSFieldString", expected: "GteCSFieldString debe ser mayor o igual a Inner.GteCSFieldString", }, { ns: "Test.NeCSFieldString", expected: "NeCSFieldString no puede ser igual a Inner.NeCSFieldString", }, { ns: "Test.EqCSFieldString", expected: "EqCSFieldString debe ser igual a Inner.EqCSFieldString", }, { ns: "Test.EqFieldString", expected: "EqFieldString debe ser igual a MaxString", }, { ns: "Test.GteString", expected: "GteString debe tener al menos 3 caracteres de longitud", }, { ns: "Test.GteNumber", expected: "GteNumber debe ser 5,56 o mayor", }, { ns: "Test.GteMultiple", expected: "GteMultiple debe contener al menos 2 elementos", }, { ns: "Test.GteTime", expected: "GteTime debe ser después o durante la fecha y hora actuales", }, { ns: "Test.GtString", expected: "GtString debe ser mayor que 3 caracteres en longitud", }, { ns: "Test.GtNumber", expected: "GtNumber debe ser mayor que 5,56", }, { ns: "Test.GtMultiple", expected: "GtMultiple debe contener más de 2 elementos", }, { ns: "Test.GtTime", expected: "GtTime debe ser después de la fecha y hora actual", }, { ns: "Test.LteString", expected: "LteString debe tener un máximo de 3 caracteres de longitud", }, { ns: "Test.LteNumber", expected: "LteNumber debe ser 5,56 o menos", }, { ns: "Test.LteMultiple", expected: "LteMultiple debe contener como máximo 2 elementos", }, { ns: "Test.LteTime", expected: "LteTime debe ser antes o durante la fecha y hora actual", }, { ns: "Test.LtString", expected: "LtString debe tener menos de 3 caracteres de longitud", }, { ns: "Test.LtNumber", expected: "LtNumber debe ser menos de 5,56", }, { ns: "Test.LtMultiple", expected: "LtMultiple debe contener menos de 2 elementos", }, { ns: "Test.LtTime", expected: "LtTime debe ser antes de la fecha y hora actual", }, { ns: "Test.NeString", expected: "NeString no debería ser igual a ", }, { ns: "Test.NeNumber", expected: "NeNumber no debería ser igual a 0.00", }, { ns: "Test.NeMultiple", expected: "NeMultiple no debería ser igual a 0", }, { ns: "Test.EqString", expected: "EqString no es igual a 3", }, { ns: "Test.EqNumber", expected: "EqNumber no es igual a 2.33", }, { ns: "Test.EqMultiple", expected: "EqMultiple no es igual a 7", }, { ns: "Test.MaxString", expected: "MaxString debe tener un máximo de 3 caracteres de longitud", }, { ns: "Test.MaxNumber", expected: "MaxNumber debe ser 1.113,00 o menos", }, { ns: "Test.MaxMultiple", expected: "MaxMultiple debe contener como máximo 7 elementos", }, { ns: "Test.MinString", expected: "MinString debe tener al menos 1 carácter de longitud", }, { ns: "Test.MinNumber", expected: "MinNumber debe ser 1.113,00 o más", }, { ns: "Test.MinMultiple", expected: "MinMultiple debe contener al menos 7 elementos", }, { ns: "Test.LenString", expected: "LenString debe tener 1 carácter de longitud", }, { ns: "Test.LenNumber", expected: "LenNumber debe ser igual a 1.113,00", }, { ns: "Test.LenMultiple", expected: "LenMultiple debe contener 7 elementos", }, { ns: "Test.RequiredString", expected: "RequiredString es un campo requerido", }, { ns: "Test.RequiredNumber", expected: "RequiredNumber es un campo requerido", }, { ns: "Test.RequiredMultiple", expected: "RequiredMultiple es un campo requerido", }, { ns: "Test.StrPtrMinLen", expected: "StrPtrMinLen debe tener al menos 10 caracteres de longitud", }, { ns: "Test.StrPtrMaxLen", expected: "StrPtrMaxLen debe tener un máximo de 1 carácter de longitud", }, { ns: "Test.StrPtrLen", expected: "StrPtrLen debe tener 2 caracteres de longitud", }, { ns: "Test.StrPtrLt", expected: "StrPtrLt debe tener menos de 1 carácter de longitud", }, { ns: "Test.StrPtrLte", expected: "StrPtrLte debe tener un máximo de 1 carácter de longitud", }, { ns: "Test.StrPtrGt", expected: "StrPtrGt debe ser mayor que 10 caracteres en longitud", }, { ns: "Test.StrPtrGte", expected: "StrPtrGte debe tener al menos 10 caracteres de longitud", }, { ns: "Test.OneOfString", expected: "OneOfString debe ser uno de [red green]", }, { ns: "Test.OneOfInt", expected: "OneOfInt debe ser uno de [5 63]", }, { ns: "Test.UniqueSlice", expected: "UniqueSlice debe contener valores únicos", }, { ns: "Test.UniqueArray", expected: "UniqueArray debe contener valores únicos", }, { ns: "Test.UniqueMap", expected: "UniqueMap debe contener valores únicos", }, } for _, tt := range tests { var fe validator.FieldError for _, e := range errs { if tt.ns == e.Namespace() { fe = e break } } NotEqual(t, fe, nil) Equal(t, tt.expected, fe.Translate(trans)) } } validator-10.4.1/translations/fr/000077500000000000000000000000001374261122600167165ustar00rootroot00000000000000validator-10.4.1/translations/fr/fr.go000066400000000000000000000777171374261122600176770ustar00rootroot00000000000000package fr import ( "fmt" "log" "reflect" "strconv" "strings" "time" "github.com/go-playground/locales" ut "github.com/go-playground/universal-translator" "github.com/go-playground/validator/v10" ) // RegisterDefaultTranslations registers a set of default translations // for all built in tag's in validator; you may add your own as desired. func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (err error) { translations := []struct { tag string translation string override bool customRegisFunc validator.RegisterTranslationsFunc customTransFunc validator.TranslationFunc }{ { tag: "required", translation: "{0} est un champ obligatoire", override: false, }, { tag: "len", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("len-string", "{0} doit faire une taille de {1}", false); err != nil { return } if err = ut.AddCardinal("len-string-character", "{0} caractère", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("len-string-character", "{0} caractères", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("len-number", "{0} doit être égal à {1}", false); err != nil { return } if err = ut.Add("len-elements", "{0} doit contenir {1}", false); err != nil { return } if err = ut.AddCardinal("len-elements-element", "{0} element", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("len-elements-element", "{0} elements", locales.PluralRuleOther, false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var digits uint64 var kind reflect.Kind if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { goto END } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string c, err = ut.C("len-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("len-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string c, err = ut.C("len-elements-element", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("len-elements", fe.Field(), c) default: t, err = ut.T("len-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "min", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("min-string", "{0} doit faire une taille minimum de {1}", false); err != nil { return } if err = ut.AddCardinal("min-string-character", "{0} caractère", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("min-string-character", "{0} caractères", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("min-number", "{0} doit être égal à {1} ou plus", false); err != nil { return } if err = ut.Add("min-elements", "{0} doit contenir au moins {1}", false); err != nil { return } if err = ut.AddCardinal("min-elements-element", "{0} element", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("min-elements-element", "{0} elements", locales.PluralRuleOther, false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var digits uint64 var kind reflect.Kind if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { goto END } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string c, err = ut.C("min-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("min-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string c, err = ut.C("min-elements-element", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("min-elements", fe.Field(), c) default: t, err = ut.T("min-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "max", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("max-string", "{0} doit faire une taille maximum de {1}", false); err != nil { return } if err = ut.AddCardinal("max-string-character", "{0} caractère", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("max-string-character", "{0} caractères", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("max-number", "{0} doit être égal à {1} ou moins", false); err != nil { return } if err = ut.Add("max-elements", "{0} doit contenir au maximum {1}", false); err != nil { return } if err = ut.AddCardinal("max-elements-element", "{0} element", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("max-elements-element", "{0} elements", locales.PluralRuleOther, false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var digits uint64 var kind reflect.Kind if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { goto END } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string c, err = ut.C("max-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("max-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string c, err = ut.C("max-elements-element", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("max-elements", fe.Field(), c) default: t, err = ut.T("max-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "eq", translation: "{0} n'est pas égal à {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { fmt.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ne", translation: "{0} ne doit pas être égal à {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { fmt.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "lt", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("lt-string", "{0} doit avoir une taille inférieure à {1}", false); err != nil { return } if err = ut.AddCardinal("lt-string-character", "{0} caractère", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("lt-string-character", "{0} caractères", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lt-number", "{0} doit être inférieur à {1}", false); err != nil { return } if err = ut.Add("lt-elements", "{0} doit contenir mois de {1}", false); err != nil { return } if err = ut.AddCardinal("lt-elements-element", "{0} element", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("lt-elements-element", "{0} elements", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lt-datetime", "{0} doit être avant la date et l'heure actuelle", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("lt-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lt-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("lt-elements-element", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lt-elements", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) goto END } t, err = ut.T("lt-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("lt-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "lte", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("lte-string", "{0} doit faire une taille maximum de {1}", false); err != nil { return } if err = ut.AddCardinal("lte-string-character", "{0} caractère", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("lte-string-character", "{0} caractères", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lte-number", "{0} doit faire {1} ou moins", false); err != nil { return } if err = ut.Add("lte-elements", "{0} doit contenir un maximum de {1}", false); err != nil { return } if err = ut.AddCardinal("lte-elements-element", "{0} element", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("lte-elements-element", "{0} elements", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lte-datetime", "{0} doit être avant ou pendant la date et l'heure actuelle", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("lte-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lte-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("lte-elements-element", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lte-elements", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) goto END } t, err = ut.T("lte-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("lte-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "gt", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("gt-string", "{0} doit avoir une taille supérieur à {1}", false); err != nil { return } if err = ut.AddCardinal("gt-string-character", "{0} caractère", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("gt-string-character", "{0} caractères", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gt-number", "{0} doit être supérieur à {1}", false); err != nil { return } if err = ut.Add("gt-elements", "{0} doit contenir plus de {1}", false); err != nil { return } if err = ut.AddCardinal("gt-elements-element", "{0} element", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("gt-elements-element", "{0} elements", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gt-datetime", "{0} doit être après la date et l'heure actuelle", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("gt-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gt-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("gt-elements-element", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gt-elements", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) goto END } t, err = ut.T("gt-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("gt-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "gte", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("gte-string", "{0} doit faire une taille d'au moins {1}", false); err != nil { return } if err = ut.AddCardinal("gte-string-character", "{0} caractère", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("gte-string-character", "{0} caractères", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gte-number", "{0} doit être {1} ou plus", false); err != nil { return } if err = ut.Add("gte-elements", "{0} doit contenir au moins {1}", false); err != nil { return } if err = ut.AddCardinal("gte-elements-element", "{0} element", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("gte-elements-element", "{0} elements", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gte-datetime", "{0} doit être après ou pendant la date et l'heure actuelle", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("gte-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gte-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("gte-elements-element", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gte-elements", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) goto END } t, err = ut.T("gte-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("gte-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "eqfield", translation: "{0} doit être égal à {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "eqcsfield", translation: "{0} doit être égal à {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "necsfield", translation: "{0} ne doit pas être égal à {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtcsfield", translation: "{0} doit être supérieur à {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtecsfield", translation: "{0} doit être supérieur ou égal à {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltcsfield", translation: "{0} doit être inférieur à {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltecsfield", translation: "{0} doit être inférieur ou égal à {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "nefield", translation: "{0} ne doit pas être égal à {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtfield", translation: "{0} doit être supérieur à {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtefield", translation: "{0} doit être supérieur ou égal à {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltfield", translation: "{0} doit être inférieur à {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltefield", translation: "{0} doit être inférieur ou égal à {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "alpha", translation: "{0} ne doit contenir que des caractères alphabétiques", override: false, }, { tag: "alphanum", translation: "{0} ne doit contenir que des caractères alphanumériques", override: false, }, { tag: "numeric", translation: "{0} doit être une valeur numérique valide", override: false, }, { tag: "number", translation: "{0} doit être un nombre valid", override: false, }, { tag: "hexadecimal", translation: "{0} doit être une chaîne de caractères au format hexadécimal valide", override: false, }, { tag: "hexcolor", translation: "{0} doit être une couleur au format HEX valide", override: false, }, { tag: "rgb", translation: "{0} doit être une couleur au format RGB valide", override: false, }, { tag: "rgba", translation: "{0} doit être une couleur au format RGBA valide", override: false, }, { tag: "hsl", translation: "{0} doit être une couleur au format HSL valide", override: false, }, { tag: "hsla", translation: "{0} doit être une couleur au format HSLA valide", override: false, }, { tag: "email", translation: "{0} doit être une adresse email valide", override: false, }, { tag: "url", translation: "{0} doit être une URL valide", override: false, }, { tag: "uri", translation: "{0} doit être une URI valide", override: false, }, { tag: "base64", translation: "{0} doit être une chaîne de caractères au format Base64 valide", override: false, }, { tag: "contains", translation: "{0} doit contenir le texte '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "containsany", translation: "{0} doit contenir au moins l' un des caractères suivants '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "excludes", translation: "{0} ne doit pas contenir le texte '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "excludesall", translation: "{0} ne doit pas contenir l'un des caractères suivants '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "excludesrune", translation: "{0} ne doit pas contenir ce qui suit '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "isbn", translation: "{0} doit être un numéro ISBN valid", override: false, }, { tag: "isbn10", translation: "{0} doit être un numéro ISBN-10 valid", override: false, }, { tag: "isbn13", translation: "{0} doit être un numéro ISBN-13 valid", override: false, }, { tag: "uuid", translation: "{0} doit être un UUID valid", override: false, }, { tag: "uuid3", translation: "{0} doit être un UUID version 3 valid", override: false, }, { tag: "uuid4", translation: "{0} doit être un UUID version 4 valid", override: false, }, { tag: "uuid5", translation: "{0} doit être un UUID version 5 valid", override: false, }, { tag: "ascii", translation: "{0} ne doit contenir que des caractères ascii", override: false, }, { tag: "printascii", translation: "{0} ne doit contenir que des caractères ascii affichables", override: false, }, { tag: "multibyte", translation: "{0} doit contenir des caractères multioctets", override: false, }, { tag: "datauri", translation: "{0} doit contenir une URI data valide", override: false, }, { tag: "latitude", translation: "{0} doit contenir des coordonnées latitude valides", override: false, }, { tag: "longitude", translation: "{0} doit contenir des coordonnées longitudes valides", override: false, }, { tag: "ssn", translation: "{0} doit être un numéro SSN valide", override: false, }, { tag: "ipv4", translation: "{0} doit être une adressse IPv4 valide", override: false, }, { tag: "ipv6", translation: "{0} doit être une adressse IPv6 valide", override: false, }, { tag: "ip", translation: "{0} doit être une adressse IP valide", override: false, }, { tag: "cidr", translation: "{0} doit contenir une notation CIDR valide", override: false, }, { tag: "cidrv4", translation: "{0} doit contenir une notation CIDR valide pour une adresse IPv4", override: false, }, { tag: "cidrv6", translation: "{0} doit contenir une notation CIDR valide pour une adresse IPv6", override: false, }, { tag: "tcp_addr", translation: "{0} doit être une adressse TCP valide", override: false, }, { tag: "tcp4_addr", translation: "{0} doit être une adressse IPv4 TCP valide", override: false, }, { tag: "tcp6_addr", translation: "{0} doit être une adressse IPv6 TCP valide", override: false, }, { tag: "udp_addr", translation: "{0} doit être une adressse UDP valide", override: false, }, { tag: "udp4_addr", translation: "{0} doit être une adressse IPv4 UDP valide", override: false, }, { tag: "udp6_addr", translation: "{0} doit être une adressse IPv6 UDP valide", override: false, }, { tag: "ip_addr", translation: "{0} doit être une adresse IP résolvable", override: false, }, { tag: "ip4_addr", translation: "{0} doit être une adresse IPv4 résolvable", override: false, }, { tag: "ip6_addr", translation: "{0} doit être une adresse IPv6 résolvable", override: false, }, { tag: "unix_addr", translation: "{0} doit être une adresse UNIX résolvable", override: false, }, { tag: "mac", translation: "{0} doit contenir une adresse MAC valide", override: false, }, { tag: "iscolor", translation: "{0} doit être une couleur valide", override: false, }, { tag: "oneof", translation: "{0} doit être l'un des choix suivants [{1}]", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { s, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return s }, }, } for _, t := range translations { if t.customTransFunc != nil && t.customRegisFunc != nil { err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, t.customTransFunc) } else if t.customTransFunc != nil && t.customRegisFunc == nil { err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), t.customTransFunc) } else if t.customTransFunc == nil && t.customRegisFunc != nil { err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, translateFunc) } else { err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), translateFunc) } if err != nil { return } } return } func registrationFunc(tag string, translation string, override bool) validator.RegisterTranslationsFunc { return func(ut ut.Translator) (err error) { if err = ut.Add(tag, translation, override); err != nil { return } return } } func translateFunc(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t } validator-10.4.1/translations/fr/fr_test.go000066400000000000000000000450131374261122600207160ustar00rootroot00000000000000package fr import ( "testing" "time" french "github.com/go-playground/locales/fr" ut "github.com/go-playground/universal-translator" . "github.com/go-playground/assert/v2" "github.com/go-playground/validator/v10" ) func TestTranslations(t *testing.T) { fre := french.New() uni := ut.New(fre, fre) trans, _ := uni.GetTranslator("fr") validate := validator.New() err := RegisterDefaultTranslations(validate, trans) Equal(t, err, nil) type Inner struct { EqCSFieldString string NeCSFieldString string GtCSFieldString string GteCSFieldString string LtCSFieldString string LteCSFieldString string } type Test struct { Inner Inner RequiredString string `validate:"required"` RequiredNumber int `validate:"required"` RequiredMultiple []string `validate:"required"` LenString string `validate:"len=1"` LenNumber float64 `validate:"len=1113.00"` LenMultiple []string `validate:"len=7"` MinString string `validate:"min=1"` MinNumber float64 `validate:"min=1113.00"` MinMultiple []string `validate:"min=7"` MaxString string `validate:"max=3"` MaxNumber float64 `validate:"max=1113.00"` MaxMultiple []string `validate:"max=7"` EqString string `validate:"eq=3"` EqNumber float64 `validate:"eq=2.33"` EqMultiple []string `validate:"eq=7"` NeString string `validate:"ne="` NeNumber float64 `validate:"ne=0.00"` NeMultiple []string `validate:"ne=0"` LtString string `validate:"lt=3"` LtNumber float64 `validate:"lt=5.56"` LtMultiple []string `validate:"lt=2"` LtTime time.Time `validate:"lt"` LteString string `validate:"lte=3"` LteNumber float64 `validate:"lte=5.56"` LteMultiple []string `validate:"lte=2"` LteTime time.Time `validate:"lte"` GtString string `validate:"gt=3"` GtNumber float64 `validate:"gt=5.56"` GtMultiple []string `validate:"gt=2"` GtTime time.Time `validate:"gt"` GteString string `validate:"gte=3"` GteNumber float64 `validate:"gte=5.56"` GteMultiple []string `validate:"gte=2"` GteTime time.Time `validate:"gte"` EqFieldString string `validate:"eqfield=MaxString"` EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"` NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"` GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"` GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"` LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"` LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"` NeFieldString string `validate:"nefield=EqFieldString"` GtFieldString string `validate:"gtfield=MaxString"` GteFieldString string `validate:"gtefield=MaxString"` LtFieldString string `validate:"ltfield=MaxString"` LteFieldString string `validate:"ltefield=MaxString"` AlphaString string `validate:"alpha"` AlphanumString string `validate:"alphanum"` NumericString string `validate:"numeric"` NumberString string `validate:"number"` HexadecimalString string `validate:"hexadecimal"` HexColorString string `validate:"hexcolor"` RGBColorString string `validate:"rgb"` RGBAColorString string `validate:"rgba"` HSLColorString string `validate:"hsl"` HSLAColorString string `validate:"hsla"` Email string `validate:"email"` URL string `validate:"url"` URI string `validate:"uri"` Base64 string `validate:"base64"` Contains string `validate:"contains=purpose"` ContainsAny string `validate:"containsany=!@#$"` Excludes string `validate:"excludes=text"` ExcludesAll string `validate:"excludesall=!@#$"` ExcludesRune string `validate:"excludesrune=☻"` ISBN string `validate:"isbn"` ISBN10 string `validate:"isbn10"` ISBN13 string `validate:"isbn13"` UUID string `validate:"uuid"` UUID3 string `validate:"uuid3"` UUID4 string `validate:"uuid4"` UUID5 string `validate:"uuid5"` ASCII string `validate:"ascii"` PrintableASCII string `validate:"printascii"` MultiByte string `validate:"multibyte"` DataURI string `validate:"datauri"` Latitude string `validate:"latitude"` Longitude string `validate:"longitude"` SSN string `validate:"ssn"` IP string `validate:"ip"` IPv4 string `validate:"ipv4"` IPv6 string `validate:"ipv6"` CIDR string `validate:"cidr"` CIDRv4 string `validate:"cidrv4"` CIDRv6 string `validate:"cidrv6"` TCPAddr string `validate:"tcp_addr"` TCPAddrv4 string `validate:"tcp4_addr"` TCPAddrv6 string `validate:"tcp6_addr"` UDPAddr string `validate:"udp_addr"` UDPAddrv4 string `validate:"udp4_addr"` UDPAddrv6 string `validate:"udp6_addr"` IPAddr string `validate:"ip_addr"` IPAddrv4 string `validate:"ip4_addr"` IPAddrv6 string `validate:"ip6_addr"` UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future MAC string `validate:"mac"` IsColor string `validate:"iscolor"` StrPtrMinLen *string `validate:"min=10"` StrPtrMaxLen *string `validate:"max=1"` StrPtrLen *string `validate:"len=2"` StrPtrLt *string `validate:"lt=1"` StrPtrLte *string `validate:"lte=1"` StrPtrGt *string `validate:"gt=10"` StrPtrGte *string `validate:"gte=10"` OneOfString string `validate:"oneof=red green"` OneOfInt int `validate:"oneof=5 63"` } var test Test test.Inner.EqCSFieldString = "1234" test.Inner.GtCSFieldString = "1234" test.Inner.GteCSFieldString = "1234" test.MaxString = "1234" test.MaxNumber = 2000 test.MaxMultiple = make([]string, 9) test.LtString = "1234" test.LtNumber = 6 test.LtMultiple = make([]string, 3) test.LtTime = time.Now().Add(time.Hour * 24) test.LteString = "1234" test.LteNumber = 6 test.LteMultiple = make([]string, 3) test.LteTime = time.Now().Add(time.Hour * 24) test.LtFieldString = "12345" test.LteFieldString = "12345" test.LtCSFieldString = "1234" test.LteCSFieldString = "1234" test.AlphaString = "abc3" test.AlphanumString = "abc3!" test.NumericString = "12E.00" test.NumberString = "12E" test.Excludes = "this is some test text" test.ExcludesAll = "This is Great!" test.ExcludesRune = "Love it ☻" test.ASCII = "カタカナ" test.PrintableASCII = "カタカナ" test.MultiByte = "1234feerf" s := "toolong" test.StrPtrMaxLen = &s test.StrPtrLen = &s err = validate.Struct(test) NotEqual(t, err, nil) errs, ok := err.(validator.ValidationErrors) Equal(t, ok, true) tests := []struct { ns string expected string }{ { ns: "Test.IsColor", expected: "IsColor doit être une couleur valide", }, { ns: "Test.MAC", expected: "MAC doit contenir une adresse MAC valide", }, { ns: "Test.IPAddr", expected: "IPAddr doit être une adresse IP résolvable", }, { ns: "Test.IPAddrv4", expected: "IPAddrv4 doit être une adresse IPv4 résolvable", }, { ns: "Test.IPAddrv6", expected: "IPAddrv6 doit être une adresse IPv6 résolvable", }, { ns: "Test.UDPAddr", expected: "UDPAddr doit être une adressse UDP valide", }, { ns: "Test.UDPAddrv4", expected: "UDPAddrv4 doit être une adressse IPv4 UDP valide", }, { ns: "Test.UDPAddrv6", expected: "UDPAddrv6 doit être une adressse IPv6 UDP valide", }, { ns: "Test.TCPAddr", expected: "TCPAddr doit être une adressse TCP valide", }, { ns: "Test.TCPAddrv4", expected: "TCPAddrv4 doit être une adressse IPv4 TCP valide", }, { ns: "Test.TCPAddrv6", expected: "TCPAddrv6 doit être une adressse IPv6 TCP valide", }, { ns: "Test.CIDR", expected: "CIDR doit contenir une notation CIDR valide", }, { ns: "Test.CIDRv4", expected: "CIDRv4 doit contenir une notation CIDR valide pour une adresse IPv4", }, { ns: "Test.CIDRv6", expected: "CIDRv6 doit contenir une notation CIDR valide pour une adresse IPv6", }, { ns: "Test.SSN", expected: "SSN doit être un numéro SSN valide", }, { ns: "Test.IP", expected: "IP doit être une adressse IP valide", }, { ns: "Test.IPv4", expected: "IPv4 doit être une adressse IPv4 valide", }, { ns: "Test.IPv6", expected: "IPv6 doit être une adressse IPv6 valide", }, { ns: "Test.DataURI", expected: "DataURI doit contenir une URI data valide", }, { ns: "Test.Latitude", expected: "Latitude doit contenir des coordonnées latitude valides", }, { ns: "Test.Longitude", expected: "Longitude doit contenir des coordonnées longitudes valides", }, { ns: "Test.MultiByte", expected: "MultiByte doit contenir des caractères multioctets", }, { ns: "Test.ASCII", expected: "ASCII ne doit contenir que des caractères ascii", }, { ns: "Test.PrintableASCII", expected: "PrintableASCII ne doit contenir que des caractères ascii affichables", }, { ns: "Test.UUID", expected: "UUID doit être un UUID valid", }, { ns: "Test.UUID3", expected: "UUID3 doit être un UUID version 3 valid", }, { ns: "Test.UUID4", expected: "UUID4 doit être un UUID version 4 valid", }, { ns: "Test.UUID5", expected: "UUID5 doit être un UUID version 5 valid", }, { ns: "Test.ISBN", expected: "ISBN doit être un numéro ISBN valid", }, { ns: "Test.ISBN10", expected: "ISBN10 doit être un numéro ISBN-10 valid", }, { ns: "Test.ISBN13", expected: "ISBN13 doit être un numéro ISBN-13 valid", }, { ns: "Test.Excludes", expected: "Excludes ne doit pas contenir le texte 'text'", }, { ns: "Test.ExcludesAll", expected: "ExcludesAll ne doit pas contenir l'un des caractères suivants '!@#$'", }, { ns: "Test.ExcludesRune", expected: "ExcludesRune ne doit pas contenir ce qui suit '☻'", }, { ns: "Test.ContainsAny", expected: "ContainsAny doit contenir au moins l' un des caractères suivants '!@#$'", }, { ns: "Test.Contains", expected: "Contains doit contenir le texte 'purpose'", }, { ns: "Test.Base64", expected: "Base64 doit être une chaîne de caractères au format Base64 valide", }, { ns: "Test.Email", expected: "Email doit être une adresse email valide", }, { ns: "Test.URL", expected: "URL doit être une URL valide", }, { ns: "Test.URI", expected: "URI doit être une URI valide", }, { ns: "Test.RGBColorString", expected: "RGBColorString doit être une couleur au format RGB valide", }, { ns: "Test.RGBAColorString", expected: "RGBAColorString doit être une couleur au format RGBA valide", }, { ns: "Test.HSLColorString", expected: "HSLColorString doit être une couleur au format HSL valide", }, { ns: "Test.HSLAColorString", expected: "HSLAColorString doit être une couleur au format HSLA valide", }, { ns: "Test.HexadecimalString", expected: "HexadecimalString doit être une chaîne de caractères au format hexadécimal valide", }, { ns: "Test.HexColorString", expected: "HexColorString doit être une couleur au format HEX valide", }, { ns: "Test.NumberString", expected: "NumberString doit être un nombre valid", }, { ns: "Test.NumericString", expected: "NumericString doit être une valeur numérique valide", }, { ns: "Test.AlphanumString", expected: "AlphanumString ne doit contenir que des caractères alphanumériques", }, { ns: "Test.AlphaString", expected: "AlphaString ne doit contenir que des caractères alphabétiques", }, { ns: "Test.LtFieldString", expected: "LtFieldString doit être inférieur à MaxString", }, { ns: "Test.LteFieldString", expected: "LteFieldString doit être inférieur ou égal à MaxString", }, { ns: "Test.GtFieldString", expected: "GtFieldString doit être supérieur à MaxString", }, { ns: "Test.GteFieldString", expected: "GteFieldString doit être supérieur ou égal à MaxString", }, { ns: "Test.NeFieldString", expected: "NeFieldString ne doit pas être égal à EqFieldString", }, { ns: "Test.LtCSFieldString", expected: "LtCSFieldString doit être inférieur à Inner.LtCSFieldString", }, { ns: "Test.LteCSFieldString", expected: "LteCSFieldString doit être inférieur ou égal à Inner.LteCSFieldString", }, { ns: "Test.GtCSFieldString", expected: "GtCSFieldString doit être supérieur à Inner.GtCSFieldString", }, { ns: "Test.GteCSFieldString", expected: "GteCSFieldString doit être supérieur ou égal à Inner.GteCSFieldString", }, { ns: "Test.NeCSFieldString", expected: "NeCSFieldString ne doit pas être égal à Inner.NeCSFieldString", }, { ns: "Test.EqCSFieldString", expected: "EqCSFieldString doit être égal à Inner.EqCSFieldString", }, { ns: "Test.EqFieldString", expected: "EqFieldString doit être égal à MaxString", }, { ns: "Test.GteString", expected: "GteString doit faire une taille d'au moins 3 caractères", }, { ns: "Test.GteNumber", expected: "GteNumber doit être 5,56 ou plus", }, { ns: "Test.GteMultiple", expected: "GteMultiple doit contenir au moins 2 elements", }, { ns: "Test.GteTime", expected: "GteTime doit être après ou pendant la date et l'heure actuelle", }, { ns: "Test.GtString", expected: "GtString doit avoir une taille supérieur à 3 caractères", }, { ns: "Test.GtNumber", expected: "GtNumber doit être supérieur à 5,56", }, { ns: "Test.GtMultiple", expected: "GtMultiple doit contenir plus de 2 elements", }, { ns: "Test.GtTime", expected: "GtTime doit être après la date et l'heure actuelle", }, { ns: "Test.LteString", expected: "LteString doit faire une taille maximum de 3 caractères", }, { ns: "Test.LteNumber", expected: "LteNumber doit faire 5,56 ou moins", }, { ns: "Test.LteMultiple", expected: "LteMultiple doit contenir un maximum de 2 elements", }, { ns: "Test.LteTime", expected: "LteTime doit être avant ou pendant la date et l'heure actuelle", }, { ns: "Test.LtString", expected: "LtString doit avoir une taille inférieure à 3 caractères", }, { ns: "Test.LtNumber", expected: "LtNumber doit être inférieur à 5,56", }, { ns: "Test.LtMultiple", expected: "LtMultiple doit contenir mois de 2 elements", }, { ns: "Test.LtTime", expected: "LtTime doit être avant la date et l'heure actuelle", }, { ns: "Test.NeString", expected: "NeString ne doit pas être égal à ", }, { ns: "Test.NeNumber", expected: "NeNumber ne doit pas être égal à 0.00", }, { ns: "Test.NeMultiple", expected: "NeMultiple ne doit pas être égal à 0", }, { ns: "Test.EqString", expected: "EqString n'est pas égal à 3", }, { ns: "Test.EqNumber", expected: "EqNumber n'est pas égal à 2.33", }, { ns: "Test.EqMultiple", expected: "EqMultiple n'est pas égal à 7", }, { ns: "Test.MaxString", expected: "MaxString doit faire une taille maximum de 3 caractères", }, { ns: "Test.MaxNumber", expected: "MaxNumber doit être égal à 1 113,00 ou moins", }, { ns: "Test.MaxMultiple", expected: "MaxMultiple doit contenir au maximum 7 elements", }, { ns: "Test.MinString", expected: "MinString doit faire une taille minimum de 1 caractère", }, { ns: "Test.MinNumber", expected: "MinNumber doit être égal à 1 113,00 ou plus", }, { ns: "Test.MinMultiple", expected: "MinMultiple doit contenir au moins 7 elements", }, { ns: "Test.LenString", expected: "LenString doit faire une taille de 1 caractère", }, { ns: "Test.LenNumber", expected: "LenNumber doit être égal à 1 113,00", }, { ns: "Test.LenMultiple", expected: "LenMultiple doit contenir 7 elements", }, { ns: "Test.RequiredString", expected: "RequiredString est un champ obligatoire", }, { ns: "Test.RequiredNumber", expected: "RequiredNumber est un champ obligatoire", }, { ns: "Test.RequiredMultiple", expected: "RequiredMultiple est un champ obligatoire", }, { ns: "Test.StrPtrMinLen", expected: "StrPtrMinLen doit faire une taille minimum de 10 caractères", }, { ns: "Test.StrPtrMaxLen", expected: "StrPtrMaxLen doit faire une taille maximum de 1 caractère", }, { ns: "Test.StrPtrLen", expected: "StrPtrLen doit faire une taille de 2 caractères", }, { ns: "Test.StrPtrLt", expected: "StrPtrLt doit avoir une taille inférieure à 1 caractère", }, { ns: "Test.StrPtrLte", expected: "StrPtrLte doit faire une taille maximum de 1 caractère", }, { ns: "Test.StrPtrGt", expected: "StrPtrGt doit avoir une taille supérieur à 10 caractères", }, { ns: "Test.StrPtrGte", expected: "StrPtrGte doit faire une taille d'au moins 10 caractères", }, { ns: "Test.OneOfString", expected: "OneOfString doit être l'un des choix suivants [red green]", }, { ns: "Test.OneOfInt", expected: "OneOfInt doit être l'un des choix suivants [5 63]", }, } for _, tt := range tests { var fe validator.FieldError for _, e := range errs { if tt.ns == e.Namespace() { fe = e break } } NotEqual(t, fe, nil) Equal(t, tt.expected, fe.Translate(trans)) } } validator-10.4.1/translations/id/000077500000000000000000000000001374261122600167035ustar00rootroot00000000000000validator-10.4.1/translations/id/id.go000066400000000000000000000770131374261122600176360ustar00rootroot00000000000000package id import ( "fmt" "log" "reflect" "strconv" "strings" "time" "github.com/go-playground/locales" ut "github.com/go-playground/universal-translator" "github.com/go-playground/validator/v10" ) // RegisterDefaultTranslations registers a set of default translations // for all built in tag's in validator; you may add your own as desired. func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (err error) { translations := []struct { tag string translation string override bool customRegisFunc validator.RegisterTranslationsFunc customTransFunc validator.TranslationFunc }{ { tag: "required", translation: "{0} wajib diisi", override: false, }, { tag: "len", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("len-string", "panjang {0} harus {1}", false); err != nil { return } // if err = ut.AddCardinal("len-string-character", "{0} karakter", locales.PluralRuleOne, false); err != nil { // return // } if err = ut.AddCardinal("len-string-character", "{0} karakter", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("len-number", "{0} harus sama dengan {1}", false); err != nil { return } if err = ut.Add("len-items", "{0} harus berisi {1}", false); err != nil { return } // if err = ut.AddCardinal("len-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { // return // } if err = ut.AddCardinal("len-items-item", "{0} item", locales.PluralRuleOther, false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var digits uint64 var kind reflect.Kind if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { goto END } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string c, err = ut.C("len-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("len-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string c, err = ut.C("len-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("len-items", fe.Field(), c) default: t, err = ut.T("len-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "min", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("min-string", "panjang minimal {0} adalah {1}", false); err != nil { return } // if err = ut.AddCardinal("min-string-character", "{0} karakter", locales.PluralRuleOne, false); err != nil { // return // } if err = ut.AddCardinal("min-string-character", "{0} karakter", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("min-number", "{0} harus {1} atau lebih besar", false); err != nil { return } if err = ut.Add("min-items", "panjang minimal {0} adalah {1}", false); err != nil { return } // if err = ut.AddCardinal("min-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { // return // } if err = ut.AddCardinal("min-items-item", "{0} item", locales.PluralRuleOther, false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var digits uint64 var kind reflect.Kind if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { goto END } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string c, err = ut.C("min-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("min-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string c, err = ut.C("min-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("min-items", fe.Field(), c) default: t, err = ut.T("min-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "max", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("max-string", "panjang maksimal {0} adalah {1}", false); err != nil { return } // if err = ut.AddCardinal("max-string-character", "{0} karakter", locales.PluralRuleOne, false); err != nil { // return // } if err = ut.AddCardinal("max-string-character", "{0} karakter", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("max-number", "{0} harus {1} atau kurang", false); err != nil { return } if err = ut.Add("max-items", "{0} harus berisi maksimal {1}", false); err != nil { return } // if err = ut.AddCardinal("max-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { // return // } if err = ut.AddCardinal("max-items-item", "{0} item", locales.PluralRuleOther, false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var digits uint64 var kind reflect.Kind if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { goto END } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string c, err = ut.C("max-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("max-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string c, err = ut.C("max-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("max-items", fe.Field(), c) default: t, err = ut.T("max-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "eq", translation: "{0} tidak sama dengan {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { fmt.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ne", translation: "{0} tidak sama dengan {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { fmt.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "lt", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("lt-string", "panjang {0} harus kurang dari {1}", false); err != nil { return } // if err = ut.AddCardinal("lt-string-character", "{0} karakter", locales.PluralRuleOne, false); err != nil { // return // } if err = ut.AddCardinal("lt-string-character", "{0} karakter", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lt-number", "{0} harus kurang dari {1}", false); err != nil { return } if err = ut.Add("lt-items", "{0} harus berisi kurang dari {1}", false); err != nil { return } // if err = ut.AddCardinal("lt-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { // return // } if err = ut.AddCardinal("lt-items-item", "{0} item", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lt-datetime", "{0} harus kurang dari tanggal & waktu saat ini", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("lt-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lt-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("lt-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lt-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) goto END } t, err = ut.T("lt-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("lt-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "lte", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("lte-string", "panjang maksimal {0} adalah {1}", false); err != nil { return } // if err = ut.AddCardinal("lte-string-character", "{0} karakter", locales.PluralRuleOne, false); err != nil { // return // } if err = ut.AddCardinal("lte-string-character", "{0} karakter", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lte-number", "{0} harus {1} atau kurang", false); err != nil { return } if err = ut.Add("lte-items", "{0} harus berisi maksimal {1}", false); err != nil { return } // if err = ut.AddCardinal("lte-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { // return // } if err = ut.AddCardinal("lte-items-item", "{0} item", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lte-datetime", "{0} harus kurang dari atau sama dengan tanggal & waktu saat ini", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("lte-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lte-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("lte-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lte-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) goto END } t, err = ut.T("lte-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("lte-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "gt", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("gt-string", "panjang {0} harus lebih dari {1}", false); err != nil { return } // if err = ut.AddCardinal("gt-string-character", "{0} karakter", locales.PluralRuleOne, false); err != nil { // return // } if err = ut.AddCardinal("gt-string-character", "{0} karakter", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gt-number", "{0} harus lebih besar dari {1}", false); err != nil { return } if err = ut.Add("gt-items", "{0} harus berisi lebih dari {1}", false); err != nil { return } // if err = ut.AddCardinal("gt-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { // return // } if err = ut.AddCardinal("gt-items-item", "{0} item", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gt-datetime", "{0} harus lebih besar dari tanggal & waktu saat ini", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("gt-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gt-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("gt-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gt-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) goto END } t, err = ut.T("gt-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("gt-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "gte", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("gte-string", "panjang minimal {0} adalah {1}", false); err != nil { return } // if err = ut.AddCardinal("gte-string-character", "{0} karakter", locales.PluralRuleOne, false); err != nil { // return // } if err = ut.AddCardinal("gte-string-character", "{0} karakter", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gte-number", "{0} harus {1} atau lebih besar", false); err != nil { return } if err = ut.Add("gte-items", "{0} harus berisi setidaknya {1}", false); err != nil { return } // if err = ut.AddCardinal("gte-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { // return // } if err = ut.AddCardinal("gte-items-item", "{0} item", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gte-datetime", "{0} harus lebih besar dari atau sama dengan tanggal & waktu saat ini", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("gte-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gte-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("gte-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gte-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) goto END } t, err = ut.T("gte-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("gte-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "eqfield", translation: "{0} harus sama dengan {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "eqcsfield", translation: "{0} harus sama dengan {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "necsfield", translation: "{0} tidak sama dengan {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtcsfield", translation: "{0} harus lebih besar dari {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtecsfield", translation: "{0} harus lebih besar dari atau sama dengan {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltcsfield", translation: "{0} harus kurang dari {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltecsfield", translation: "{0} harus kurang dari atau sama dengan {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "nefield", translation: "{0} tidak sama dengan {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtfield", translation: "{0} harus lebih besar dari {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtefield", translation: "{0} harus lebih besar dari atau sama dengan {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltfield", translation: "{0} harus kurang dari {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltefield", translation: "{0} harus kurang dari atau sama dengan {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "alpha", translation: "{0} hanya dapat berisi karakter abjad", override: false, }, { tag: "alphanum", translation: "{0} hanya dapat berisi karakter alfanumerik", override: false, }, { tag: "numeric", translation: "{0} harus berupa nilai numerik yang valid", override: false, }, { tag: "number", translation: "{0} harus berupa angka yang valid", override: false, }, { tag: "hexadecimal", translation: "{0} harus berupa heksadesimal yang valid", override: false, }, { tag: "hexcolor", translation: "{0} harus berupa warna HEX yang valid", override: false, }, { tag: "rgb", translation: "{0} harus berupa warna RGB yang valid", override: false, }, { tag: "rgba", translation: "{0} harus berupa warna RGBA yang valid", override: false, }, { tag: "hsl", translation: "{0} harus berupa warna HSL yang valid", override: false, }, { tag: "hsla", translation: "{0} harus berupa warna HSLA yang valid", override: false, }, { tag: "email", translation: "{0} harus berupa alamat email yang valid", override: false, }, { tag: "url", translation: "{0} harus berupa URL yang valid", override: false, }, { tag: "uri", translation: "{0} harus berupa URI yang valid", override: false, }, { tag: "base64", translation: "{0} harus berupa string Base64 yang valid", override: false, }, { tag: "contains", translation: "{0} harus berisi teks '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "containsany", translation: "{0} harus berisi setidaknya salah satu karakter berikut '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "excludes", translation: "{0} tidak boleh berisi teks '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "excludesall", translation: "{0} tidak boleh berisi salah satu karakter berikut '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "excludesrune", translation: "{0} tidak boleh berisi '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "isbn", translation: "{0} harus berupa nomor ISBN yang valid", override: false, }, { tag: "isbn10", translation: "{0} harus berupa nomor ISBN-10 yang valid", override: false, }, { tag: "isbn13", translation: "{0} harus berupa nomor ISBN-13 yang valid", override: false, }, { tag: "uuid", translation: "{0} harus berupa UUID yang valid", override: false, }, { tag: "uuid3", translation: "{0} harus berupa UUID versi 3 yang valid", override: false, }, { tag: "uuid4", translation: "{0} harus berupa UUID versi 4 yang valid", override: false, }, { tag: "uuid5", translation: "{0} harus berupa UUID versi 5 yang valid", override: false, }, { tag: "ascii", translation: "{0} hanya boleh berisi karakter ascii", override: false, }, { tag: "printascii", translation: "{0} hanya boleh berisi karakter ascii yang dapat dicetak", override: false, }, { tag: "multibyte", translation: "{0} harus berisi karakter multibyte", override: false, }, { tag: "datauri", translation: "{0} harus berisi URI Data yang valid", override: false, }, { tag: "latitude", translation: "{0} harus berisi koordinat lintang yang valid", override: false, }, { tag: "longitude", translation: "{0} harus berisi koordinat bujur yang valid", override: false, }, { tag: "ssn", translation: "{0} harus berupa nomor SSN yang valid", override: false, }, { tag: "ipv4", translation: "{0} harus berupa alamat IPv4 yang valid", override: false, }, { tag: "ipv6", translation: "{0} harus berupa alamat IPv6 yang valid", override: false, }, { tag: "ip", translation: "{0} harus berupa alamat IP yang valid", override: false, }, { tag: "cidr", translation: "{0} harus berisi notasi CIDR yang valid", override: false, }, { tag: "cidrv4", translation: "{0} harus berisi notasi CIDR yang valid untuk alamat IPv4", override: false, }, { tag: "cidrv6", translation: "{0} harus berisi notasi CIDR yang valid untuk alamat IPv6", override: false, }, { tag: "tcp_addr", translation: "{0} harus berupa alamat TCP yang valid", override: false, }, { tag: "tcp4_addr", translation: "{0} harus berupa alamat TCP IPv4 yang valid", override: false, }, { tag: "tcp6_addr", translation: "{0} harus berupa alamat TCP IPv6 yang valid", override: false, }, { tag: "udp_addr", translation: "{0} harus berupa alamat UDP yang valid", override: false, }, { tag: "udp4_addr", translation: "{0} harus berupa alamat IPv4 UDP yang valid", override: false, }, { tag: "udp6_addr", translation: "{0} harus berupa alamat IPv6 UDP yang valid", override: false, }, { tag: "ip_addr", translation: "{0} harus berupa alamat IP yang dapat dipecahkan", override: false, }, { tag: "ip4_addr", translation: "{0} harus berupa alamat IPv4 yang dapat diatasi", override: false, }, { tag: "ip6_addr", translation: "{0} harus berupa alamat IPv6 yang dapat diatasi", override: false, }, { tag: "unix_addr", translation: "{0} harus berupa alamat UNIX yang dapat diatasi", override: false, }, { tag: "mac", translation: "{0} harus berisi alamat MAC yang valid", override: false, }, { tag: "iscolor", translation: "{0} harus berupa warna yang valid", override: false, }, { tag: "oneof", translation: "{0} harus berupa salah satu dari [{1}]", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { s, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return s }, }, } for _, t := range translations { if t.customTransFunc != nil && t.customRegisFunc != nil { err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, t.customTransFunc) } else if t.customTransFunc != nil && t.customRegisFunc == nil { err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), t.customTransFunc) } else if t.customTransFunc == nil && t.customRegisFunc != nil { err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, translateFunc) } else { err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), translateFunc) } if err != nil { return } } return } func registrationFunc(tag string, translation string, override bool) validator.RegisterTranslationsFunc { return func(ut ut.Translator) (err error) { if err = ut.Add(tag, translation, override); err != nil { return } return } } func translateFunc(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t } validator-10.4.1/translations/id/id_test.go000066400000000000000000000440121374261122600206660ustar00rootroot00000000000000package id import ( "testing" "time" indonesia "github.com/go-playground/locales/id" ut "github.com/go-playground/universal-translator" . "github.com/go-playground/assert/v2" "github.com/go-playground/validator/v10" ) func TestTranslations(t *testing.T) { idn := indonesia.New() uni := ut.New(idn, idn) trans, _ := uni.GetTranslator("id") validate := validator.New() err := RegisterDefaultTranslations(validate, trans) Equal(t, err, nil) type Inner struct { EqCSFieldString string NeCSFieldString string GtCSFieldString string GteCSFieldString string LtCSFieldString string LteCSFieldString string } type Test struct { Inner Inner RequiredString string `validate:"required"` RequiredNumber int `validate:"required"` RequiredMultiple []string `validate:"required"` LenString string `validate:"len=1"` LenNumber float64 `validate:"len=1113.00"` LenMultiple []string `validate:"len=7"` MinString string `validate:"min=1"` MinNumber float64 `validate:"min=1113.00"` MinMultiple []string `validate:"min=7"` MaxString string `validate:"max=3"` MaxNumber float64 `validate:"max=1113.00"` MaxMultiple []string `validate:"max=7"` EqString string `validate:"eq=3"` EqNumber float64 `validate:"eq=2.33"` EqMultiple []string `validate:"eq=7"` NeString string `validate:"ne="` NeNumber float64 `validate:"ne=0.00"` NeMultiple []string `validate:"ne=0"` LtString string `validate:"lt=3"` LtNumber float64 `validate:"lt=5.56"` LtMultiple []string `validate:"lt=2"` LtTime time.Time `validate:"lt"` LteString string `validate:"lte=3"` LteNumber float64 `validate:"lte=5.56"` LteMultiple []string `validate:"lte=2"` LteTime time.Time `validate:"lte"` GtString string `validate:"gt=3"` GtNumber float64 `validate:"gt=5.56"` GtMultiple []string `validate:"gt=2"` GtTime time.Time `validate:"gt"` GteString string `validate:"gte=3"` GteNumber float64 `validate:"gte=5.56"` GteMultiple []string `validate:"gte=2"` GteTime time.Time `validate:"gte"` EqFieldString string `validate:"eqfield=MaxString"` EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"` NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"` GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"` GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"` LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"` LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"` NeFieldString string `validate:"nefield=EqFieldString"` GtFieldString string `validate:"gtfield=MaxString"` GteFieldString string `validate:"gtefield=MaxString"` LtFieldString string `validate:"ltfield=MaxString"` LteFieldString string `validate:"ltefield=MaxString"` AlphaString string `validate:"alpha"` AlphanumString string `validate:"alphanum"` NumericString string `validate:"numeric"` NumberString string `validate:"number"` HexadecimalString string `validate:"hexadecimal"` HexColorString string `validate:"hexcolor"` RGBColorString string `validate:"rgb"` RGBAColorString string `validate:"rgba"` HSLColorString string `validate:"hsl"` HSLAColorString string `validate:"hsla"` Email string `validate:"email"` URL string `validate:"url"` URI string `validate:"uri"` Base64 string `validate:"base64"` Contains string `validate:"contains=tujuan"` ContainsAny string `validate:"containsany=!@#$"` Excludes string `validate:"excludes=text"` ExcludesAll string `validate:"excludesall=!@#$"` ExcludesRune string `validate:"excludesrune=☻"` ISBN string `validate:"isbn"` ISBN10 string `validate:"isbn10"` ISBN13 string `validate:"isbn13"` UUID string `validate:"uuid"` UUID3 string `validate:"uuid3"` UUID4 string `validate:"uuid4"` UUID5 string `validate:"uuid5"` ASCII string `validate:"ascii"` PrintableASCII string `validate:"printascii"` MultiByte string `validate:"multibyte"` DataURI string `validate:"datauri"` Latitude string `validate:"latitude"` Longitude string `validate:"longitude"` SSN string `validate:"ssn"` IP string `validate:"ip"` IPv4 string `validate:"ipv4"` IPv6 string `validate:"ipv6"` CIDR string `validate:"cidr"` CIDRv4 string `validate:"cidrv4"` CIDRv6 string `validate:"cidrv6"` TCPAddr string `validate:"tcp_addr"` TCPAddrv4 string `validate:"tcp4_addr"` TCPAddrv6 string `validate:"tcp6_addr"` UDPAddr string `validate:"udp_addr"` UDPAddrv4 string `validate:"udp4_addr"` UDPAddrv6 string `validate:"udp6_addr"` IPAddr string `validate:"ip_addr"` IPAddrv4 string `validate:"ip4_addr"` IPAddrv6 string `validate:"ip6_addr"` UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future MAC string `validate:"mac"` IsColor string `validate:"iscolor"` StrPtrMinLen *string `validate:"min=10"` StrPtrMaxLen *string `validate:"max=1"` StrPtrLen *string `validate:"len=2"` StrPtrLt *string `validate:"lt=1"` StrPtrLte *string `validate:"lte=1"` StrPtrGt *string `validate:"gt=10"` StrPtrGte *string `validate:"gte=10"` OneOfString string `validate:"oneof=merah hijau"` OneOfInt int `validate:"oneof=5 63"` } var test Test test.Inner.EqCSFieldString = "1234" test.Inner.GtCSFieldString = "1234" test.Inner.GteCSFieldString = "1234" test.MaxString = "1234" test.MaxNumber = 2000 test.MaxMultiple = make([]string, 9) test.LtString = "1234" test.LtNumber = 6 test.LtMultiple = make([]string, 3) test.LtTime = time.Now().Add(time.Hour * 24) test.LteString = "1234" test.LteNumber = 6 test.LteMultiple = make([]string, 3) test.LteTime = time.Now().Add(time.Hour * 24) test.LtFieldString = "12345" test.LteFieldString = "12345" test.LtCSFieldString = "1234" test.LteCSFieldString = "1234" test.AlphaString = "abc3" test.AlphanumString = "abc3!" test.NumericString = "12E.00" test.NumberString = "12E" test.Excludes = "this is some test text" test.ExcludesAll = "This is Great!" test.ExcludesRune = "Love it ☻" test.ASCII = "カタカナ" test.PrintableASCII = "カタカナ" test.MultiByte = "1234feerf" s := "toolong" test.StrPtrMaxLen = &s test.StrPtrLen = &s err = validate.Struct(test) NotEqual(t, err, nil) errs, ok := err.(validator.ValidationErrors) Equal(t, ok, true) tests := []struct { ns string expected string }{ { ns: "Test.IsColor", expected: "IsColor harus berupa warna yang valid", }, { ns: "Test.MAC", expected: "MAC harus berisi alamat MAC yang valid", }, { ns: "Test.IPAddr", expected: "IPAddr harus berupa alamat IP yang dapat dipecahkan", }, { ns: "Test.IPAddrv4", expected: "IPAddrv4 harus berupa alamat IPv4 yang dapat diatasi", }, { ns: "Test.IPAddrv6", expected: "IPAddrv6 harus berupa alamat IPv6 yang dapat diatasi", }, { ns: "Test.UDPAddr", expected: "UDPAddr harus berupa alamat UDP yang valid", }, { ns: "Test.UDPAddrv4", expected: "UDPAddrv4 harus berupa alamat IPv4 UDP yang valid", }, { ns: "Test.UDPAddrv6", expected: "UDPAddrv6 harus berupa alamat IPv6 UDP yang valid", }, { ns: "Test.TCPAddr", expected: "TCPAddr harus berupa alamat TCP yang valid", }, { ns: "Test.TCPAddrv4", expected: "TCPAddrv4 harus berupa alamat TCP IPv4 yang valid", }, { ns: "Test.TCPAddrv6", expected: "TCPAddrv6 harus berupa alamat TCP IPv6 yang valid", }, { ns: "Test.CIDR", expected: "CIDR harus berisi notasi CIDR yang valid", }, { ns: "Test.CIDRv4", expected: "CIDRv4 harus berisi notasi CIDR yang valid untuk alamat IPv4", }, { ns: "Test.CIDRv6", expected: "CIDRv6 harus berisi notasi CIDR yang valid untuk alamat IPv6", }, { ns: "Test.SSN", expected: "SSN harus berupa nomor SSN yang valid", }, { ns: "Test.IP", expected: "IP harus berupa alamat IP yang valid", }, { ns: "Test.IPv4", expected: "IPv4 harus berupa alamat IPv4 yang valid", }, { ns: "Test.IPv6", expected: "IPv6 harus berupa alamat IPv6 yang valid", }, { ns: "Test.DataURI", expected: "DataURI harus berisi URI Data yang valid", }, { ns: "Test.Latitude", expected: "Latitude harus berisi koordinat lintang yang valid", }, { ns: "Test.Longitude", expected: "Longitude harus berisi koordinat bujur yang valid", }, { ns: "Test.MultiByte", expected: "MultiByte harus berisi karakter multibyte", }, { ns: "Test.ASCII", expected: "ASCII hanya boleh berisi karakter ascii", }, { ns: "Test.PrintableASCII", expected: "PrintableASCII hanya boleh berisi karakter ascii yang dapat dicetak", }, { ns: "Test.UUID", expected: "UUID harus berupa UUID yang valid", }, { ns: "Test.UUID3", expected: "UUID3 harus berupa UUID versi 3 yang valid", }, { ns: "Test.UUID4", expected: "UUID4 harus berupa UUID versi 4 yang valid", }, { ns: "Test.UUID5", expected: "UUID5 harus berupa UUID versi 5 yang valid", }, { ns: "Test.ISBN", expected: "ISBN harus berupa nomor ISBN yang valid", }, { ns: "Test.ISBN10", expected: "ISBN10 harus berupa nomor ISBN-10 yang valid", }, { ns: "Test.ISBN13", expected: "ISBN13 harus berupa nomor ISBN-13 yang valid", }, { ns: "Test.Excludes", expected: "Excludes tidak boleh berisi teks 'text'", }, { ns: "Test.ExcludesAll", expected: "ExcludesAll tidak boleh berisi salah satu karakter berikut '!@#$'", }, { ns: "Test.ExcludesRune", expected: "ExcludesRune tidak boleh berisi '☻'", }, { ns: "Test.ContainsAny", expected: "ContainsAny harus berisi setidaknya salah satu karakter berikut '!@#$'", }, { ns: "Test.Contains", expected: "Contains harus berisi teks 'tujuan'", }, { ns: "Test.Base64", expected: "Base64 harus berupa string Base64 yang valid", }, { ns: "Test.Email", expected: "Email harus berupa alamat email yang valid", }, { ns: "Test.URL", expected: "URL harus berupa URL yang valid", }, { ns: "Test.URI", expected: "URI harus berupa URI yang valid", }, { ns: "Test.RGBColorString", expected: "RGBColorString harus berupa warna RGB yang valid", }, { ns: "Test.RGBAColorString", expected: "RGBAColorString harus berupa warna RGBA yang valid", }, { ns: "Test.HSLColorString", expected: "HSLColorString harus berupa warna HSL yang valid", }, { ns: "Test.HSLAColorString", expected: "HSLAColorString harus berupa warna HSLA yang valid", }, { ns: "Test.HexadecimalString", expected: "HexadecimalString harus berupa heksadesimal yang valid", }, { ns: "Test.HexColorString", expected: "HexColorString harus berupa warna HEX yang valid", }, { ns: "Test.NumberString", expected: "NumberString harus berupa angka yang valid", }, { ns: "Test.NumericString", expected: "NumericString harus berupa nilai numerik yang valid", }, { ns: "Test.AlphanumString", expected: "AlphanumString hanya dapat berisi karakter alfanumerik", }, { ns: "Test.AlphaString", expected: "AlphaString hanya dapat berisi karakter abjad", }, { ns: "Test.LtFieldString", expected: "LtFieldString harus kurang dari MaxString", }, { ns: "Test.LteFieldString", expected: "LteFieldString harus kurang dari atau sama dengan MaxString", }, { ns: "Test.GtFieldString", expected: "GtFieldString harus lebih besar dari MaxString", }, { ns: "Test.GteFieldString", expected: "GteFieldString harus lebih besar dari atau sama dengan MaxString", }, { ns: "Test.NeFieldString", expected: "NeFieldString tidak sama dengan EqFieldString", }, { ns: "Test.LtCSFieldString", expected: "LtCSFieldString harus kurang dari Inner.LtCSFieldString", }, { ns: "Test.LteCSFieldString", expected: "LteCSFieldString harus kurang dari atau sama dengan Inner.LteCSFieldString", }, { ns: "Test.GtCSFieldString", expected: "GtCSFieldString harus lebih besar dari Inner.GtCSFieldString", }, { ns: "Test.GteCSFieldString", expected: "GteCSFieldString harus lebih besar dari atau sama dengan Inner.GteCSFieldString", }, { ns: "Test.NeCSFieldString", expected: "NeCSFieldString tidak sama dengan Inner.NeCSFieldString", }, { ns: "Test.EqCSFieldString", expected: "EqCSFieldString harus sama dengan Inner.EqCSFieldString", }, { ns: "Test.EqFieldString", expected: "EqFieldString harus sama dengan MaxString", }, { ns: "Test.GteString", expected: "panjang minimal GteString adalah 3 karakter", }, { ns: "Test.GteNumber", expected: "GteNumber harus 5,56 atau lebih besar", }, { ns: "Test.GteMultiple", expected: "GteMultiple harus berisi setidaknya 2 item", }, { ns: "Test.GteTime", expected: "GteTime harus lebih besar dari atau sama dengan tanggal & waktu saat ini", }, { ns: "Test.GtString", expected: "panjang GtString harus lebih dari 3 karakter", }, { ns: "Test.GtNumber", expected: "GtNumber harus lebih besar dari 5,56", }, { ns: "Test.GtMultiple", expected: "GtMultiple harus berisi lebih dari 2 item", }, { ns: "Test.GtTime", expected: "GtTime harus lebih besar dari tanggal & waktu saat ini", }, { ns: "Test.LteString", expected: "panjang maksimal LteString adalah 3 karakter", }, { ns: "Test.LteNumber", expected: "LteNumber harus 5,56 atau kurang", }, { ns: "Test.LteMultiple", expected: "LteMultiple harus berisi maksimal 2 item", }, { ns: "Test.LteTime", expected: "LteTime harus kurang dari atau sama dengan tanggal & waktu saat ini", }, { ns: "Test.LtString", expected: "panjang LtString harus kurang dari 3 karakter", }, { ns: "Test.LtNumber", expected: "LtNumber harus kurang dari 5,56", }, { ns: "Test.LtMultiple", expected: "LtMultiple harus berisi kurang dari 2 item", }, { ns: "Test.LtTime", expected: "LtTime harus kurang dari tanggal & waktu saat ini", }, { ns: "Test.NeString", expected: "NeString tidak sama dengan ", }, { ns: "Test.NeNumber", expected: "NeNumber tidak sama dengan 0.00", }, { ns: "Test.NeMultiple", expected: "NeMultiple tidak sama dengan 0", }, { ns: "Test.EqString", expected: "EqString tidak sama dengan 3", }, { ns: "Test.EqNumber", expected: "EqNumber tidak sama dengan 2.33", }, { ns: "Test.EqMultiple", expected: "EqMultiple tidak sama dengan 7", }, { ns: "Test.MaxString", expected: "panjang maksimal MaxString adalah 3 karakter", }, { ns: "Test.MaxNumber", expected: "MaxNumber harus 1.113,00 atau kurang", }, { ns: "Test.MaxMultiple", expected: "MaxMultiple harus berisi maksimal 7 item", }, { ns: "Test.MinString", expected: "panjang minimal MinString adalah 1 karakter", }, { ns: "Test.MinNumber", expected: "MinNumber harus 1.113,00 atau lebih besar", }, { ns: "Test.MinMultiple", expected: "panjang minimal MinMultiple adalah 7 item", }, { ns: "Test.LenString", expected: "panjang LenString harus 1 karakter", }, { ns: "Test.LenNumber", expected: "LenNumber harus sama dengan 1.113,00", }, { ns: "Test.LenMultiple", expected: "LenMultiple harus berisi 7 item", }, { ns: "Test.RequiredString", expected: "RequiredString wajib diisi", }, { ns: "Test.RequiredNumber", expected: "RequiredNumber wajib diisi", }, { ns: "Test.RequiredMultiple", expected: "RequiredMultiple wajib diisi", }, { ns: "Test.StrPtrMinLen", expected: "panjang minimal StrPtrMinLen adalah 10 karakter", }, { ns: "Test.StrPtrMaxLen", expected: "panjang maksimal StrPtrMaxLen adalah 1 karakter", }, { ns: "Test.StrPtrLen", expected: "panjang StrPtrLen harus 2 karakter", }, { ns: "Test.StrPtrLt", expected: "panjang StrPtrLt harus kurang dari 1 karakter", }, { ns: "Test.StrPtrLte", expected: "panjang maksimal StrPtrLte adalah 1 karakter", }, { ns: "Test.StrPtrGt", expected: "panjang StrPtrGt harus lebih dari 10 karakter", }, { ns: "Test.StrPtrGte", expected: "panjang minimal StrPtrGte adalah 10 karakter", }, { ns: "Test.OneOfString", expected: "OneOfString harus berupa salah satu dari [merah hijau]", }, { ns: "Test.OneOfInt", expected: "OneOfInt harus berupa salah satu dari [5 63]", }, } for _, tt := range tests { var fe validator.FieldError for _, e := range errs { if tt.ns == e.Namespace() { fe = e break } } NotEqual(t, fe, nil) Equal(t, tt.expected, fe.Translate(trans)) } } validator-10.4.1/translations/ja/000077500000000000000000000000001374261122600167015ustar00rootroot00000000000000validator-10.4.1/translations/ja/ja.go000066400000000000000000001055301374261122600176260ustar00rootroot00000000000000package ja import ( "fmt" "log" "reflect" "strconv" "strings" "time" "github.com/go-playground/locales" ut "github.com/go-playground/universal-translator" "github.com/go-playground/validator/v10" ) // RegisterDefaultTranslations registers a set of default translations // for all built in tag's in validator; you may add your own as desired. func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (err error) { translations := []struct { tag string translation string override bool customRegisFunc validator.RegisterTranslationsFunc customTransFunc validator.TranslationFunc }{ { tag: "required", translation: "{0}は必須フィールドです", override: false, }, { tag: "len", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("len-string", "{0}の長さは{1}でなければなりません", false); err != nil { return } // if err = ut.AddCardinal("len-string-character", "{0}文字", locales.PluralRuleOne, false); err != nil { // return // } if err = ut.AddCardinal("len-string-character", "{0}文字", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("len-number", "{0}は{1}と等しくなければなりません", false); err != nil { return } if err = ut.Add("len-items", "{0}は{1}を含まなければなりません", false); err != nil { return } // if err = ut.AddCardinal("len-items-item", "{0}つの項目", locales.PluralRuleOne, false); err != nil { // return // } if err = ut.AddCardinal("len-items-item", "{0}つの項目", locales.PluralRuleOther, false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var digits uint64 var kind reflect.Kind if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { goto END } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string c, err = ut.C("len-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("len-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string c, err = ut.C("len-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("len-items", fe.Field(), c) default: t, err = ut.T("len-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "min", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("min-string", "{0}の長さは少なくとも{1}はなければなりません", false); err != nil { return } // if err = ut.AddCardinal("min-string-character", "{0}文字", locales.PluralRuleOne, false); err != nil { // return // } if err = ut.AddCardinal("min-string-character", "{0}文字", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("min-number", "{0}は{1}かより大きくなければなりません", false); err != nil { return } if err = ut.Add("min-items", "{0}は少なくとも{1}を含まなければなりません", false); err != nil { return } // if err = ut.AddCardinal("min-items-item", "{0}つの項目", locales.PluralRuleOne, false); err != nil { // return // } if err = ut.AddCardinal("min-items-item", "{0}つの項目", locales.PluralRuleOther, false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var digits uint64 var kind reflect.Kind if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { goto END } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string c, err = ut.C("min-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("min-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string c, err = ut.C("min-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("min-items", fe.Field(), c) default: t, err = ut.T("min-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "max", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("max-string", "{0}の長さは最大でも{1}でなければなりません", false); err != nil { return } // if err = ut.AddCardinal("max-string-character", "{0}文字", locales.PluralRuleOne, false); err != nil { // return // } if err = ut.AddCardinal("max-string-character", "{0}文字", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("max-number", "{0}は{1}かより小さくなければなりません", false); err != nil { return } if err = ut.Add("max-items", "{0}は最大でも{1}を含まなければなりません", false); err != nil { return } // if err = ut.AddCardinal("max-items-item", "{0}つの項目", locales.PluralRuleOne, false); err != nil { // return // } if err = ut.AddCardinal("max-items-item", "{0}つの項目", locales.PluralRuleOther, false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var digits uint64 var kind reflect.Kind if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { goto END } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string c, err = ut.C("max-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("max-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string c, err = ut.C("max-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("max-items", fe.Field(), c) default: t, err = ut.T("max-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "eq", translation: "{0}は{1}と等しくありません", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { fmt.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ne", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("ne-items", "{0}の項目の数は{1}と異ならなければなりません", false); err != nil { fmt.Printf("ne customRegisFunc #1 error because of %v\n", err) return } // if err = ut.AddCardinal("ne-items-item", "{0}個", locales.PluralRuleOne, false); err != nil { // return // } if err = ut.AddCardinal("ne-items-item", "{0}個", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("ne", "{0}は{1}と異ならなければなりません", false); err != nil { fmt.Printf("ne customRegisFunc #2 error because of %v\n", err) return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.Slice: var c string err = fn() if err != nil { goto END } c, err = ut.C("ne-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("ne-items", fe.Field(), c) default: t, err = ut.T("ne", fe.Field(), fe.Param()) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "lt", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("lt-string", "{0}の長さは{1}よりも少なくなければなりません", false); err != nil { return } // if err = ut.AddCardinal("lt-string-character", "{0}文字", locales.PluralRuleOne, false); err != nil { // return // } if err = ut.AddCardinal("lt-string-character", "{0}文字", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lt-number", "{0}は{1}よりも小さくなければなりません", false); err != nil { return } if err = ut.Add("lt-items", "{0}は{1}よりも少ない項目を含まなければなりません", false); err != nil { return } // if err = ut.AddCardinal("lt-items-item", "{0}つの項目", locales.PluralRuleOne, false); err != nil { // return // } if err = ut.AddCardinal("lt-items-item", "{0}つの項目", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lt-datetime", "{0}は現時刻よりも前でなければなりません", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("lt-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lt-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("lt-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lt-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) goto END } t, err = ut.T("lt-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("lt-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "lte", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("lte-string", "{0}の長さは最大でも{1}でなければなりません", false); err != nil { return } // if err = ut.AddCardinal("lte-string-character", "{0}文字", locales.PluralRuleOne, false); err != nil { // return // } if err = ut.AddCardinal("lte-string-character", "{0}文字", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lte-number", "{0}は{1}かより小さくなければなりません", false); err != nil { return } if err = ut.Add("lte-items", "{0}は最大でも{1}を含まなければなりません", false); err != nil { return } // if err = ut.AddCardinal("lte-items-item", "{0}つの項目", locales.PluralRuleOne, false); err != nil { // return // } if err = ut.AddCardinal("lte-items-item", "{0}つの項目", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lte-datetime", "{0}は現時刻以前でなければなりません", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("lte-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lte-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("lte-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lte-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) goto END } t, err = ut.T("lte-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("lte-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "gt", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("gt-string", "{0}の長さは{1}よりも多くなければなりません", false); err != nil { return } // if err = ut.AddCardinal("gt-string-character", "{0}文字", locales.PluralRuleOne, false); err != nil { // return // } if err = ut.AddCardinal("gt-string-character", "{0}文字", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gt-number", "{0}は{1}よりも大きくなければなりません", false); err != nil { return } if err = ut.Add("gt-items", "{0}は{1}よりも多い項目を含まなければなりません", false); err != nil { return } // if err = ut.AddCardinal("gt-items-item", "{0}つの項目", locales.PluralRuleOne, false); err != nil { // return // } if err = ut.AddCardinal("gt-items-item", "{0}つの項目", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gt-datetime", "{0}は現時刻よりも後でなければなりません", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("gt-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gt-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("gt-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gt-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) goto END } t, err = ut.T("gt-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("gt-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "gte", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("gte-string", "{0}の長さは少なくとも{1}以上はなければなりません", false); err != nil { return } // if err = ut.AddCardinal("gte-string-character", "{0}文字", locales.PluralRuleOne, false); err != nil { // return // } if err = ut.AddCardinal("gte-string-character", "{0}文字", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gte-number", "{0}は{1}かより大きくなければなりません", false); err != nil { return } if err = ut.Add("gte-items", "{0}は少なくとも{1}を含まなければなりません", false); err != nil { return } // if err = ut.AddCardinal("gte-items-item", "{0}つの項目", locales.PluralRuleOne, false); err != nil { // return // } if err = ut.AddCardinal("gte-items-item", "{0}つの項目", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gte-datetime", "{0}は現時刻以降でなければなりません", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("gte-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gte-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("gte-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gte-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) goto END } t, err = ut.T("gte-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("gte-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "eqfield", translation: "{0}は{1}と等しくなければなりません", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "eqcsfield", translation: "{0}は{1}と等しくなければなりません", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "necsfield", translation: "{0}は{1}とは異ならなければなりません", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtcsfield", translation: "{0}は{1}よりも大きくなければなりません", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtecsfield", translation: "{0}は{1}以上でなければなりません", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltcsfield", translation: "{0}は{1}よりも小さくなければなりません", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltecsfield", translation: "{0}は{1}以下でなければなりません", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "nefield", translation: "{0}は{1}とは異ならなければなりません", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtfield", translation: "{0}は{1}よりも大きくなければなりません", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtefield", translation: "{0}は{1}以上でなければなりません", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltfield", translation: "{0}は{1}よりも小さくなければなりません", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltefield", translation: "{0}は{1}以下でなければなりません", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "alpha", translation: "{0}はアルファベットのみを含むことができます", override: false, }, { tag: "alphanum", translation: "{0}はアルファベットと数字のみを含むことができます", override: false, }, { tag: "numeric", translation: "{0}は正しい数字でなければなりません", override: false, }, { tag: "number", translation: "{0}は正しい数でなければなりません", override: false, }, { tag: "hexadecimal", translation: "{0}は正しい16進表記でなければなりません", override: false, }, { tag: "hexcolor", translation: "{0}は正しいHEXカラーコードでなければなりません", override: false, }, { tag: "rgb", translation: "{0}は正しいRGBカラーコードでなければなりません", override: false, }, { tag: "rgba", translation: "{0}は正しいRGBAカラーコードでなければなりません", override: false, }, { tag: "hsl", translation: "{0}は正しいHSLカラーコードでなければなりません", override: false, }, { tag: "hsla", translation: "{0}は正しいHSLAカラーコードでなければなりません", override: false, }, { tag: "email", translation: "{0}は正しいメールアドレスでなければなりません", override: false, }, { tag: "url", translation: "{0}は正しいURLでなければなりません", override: false, }, { tag: "uri", translation: "{0}は正しいURIでなければなりません", override: false, }, { tag: "base64", translation: "{0}は正しいBase64文字列でなければなりません", override: false, }, { tag: "contains", translation: "{0}は'{1}'を含まなければなりません", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "containsany", translation: "{0}は'{1}'の少なくとも1つを含まなければなりません", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "excludes", translation: "{0}には'{1}'というテキストを含むことはできません", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "excludesall", translation: "{0}には'{1}'のどれも含めることはできません", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "excludesrune", translation: "{0}には'{1}'を含めることはできません", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "isbn", translation: "{0}は正しいISBN番号でなければなりません", override: false, }, { tag: "isbn10", translation: "{0}は正しいISBN-10番号でなければなりません", override: false, }, { tag: "isbn13", translation: "{0}は正しいISBN-13番号でなければなりません", override: false, }, { tag: "uuid", translation: "{0}は正しいUUIDでなければなりません", override: false, }, { tag: "uuid3", translation: "{0}はバージョンが3の正しいUUIDでなければなりません", override: false, }, { tag: "uuid4", translation: "{0}はバージョンが4の正しいUUIDでなければなりません", override: false, }, { tag: "uuid5", translation: "{0}はバージョンが4の正しいUUIDでなければなりません", override: false, }, { tag: "ascii", translation: "{0}はASCII文字のみを含まなければなりません", override: false, }, { tag: "printascii", translation: "{0}は印刷可能なASCII文字のみを含まなければなりません", override: false, }, { tag: "multibyte", translation: "{0}はマルチバイト文字を含まなければなりません", override: false, }, { tag: "datauri", translation: "{0}は正しいデータURIを含まなければなりません", override: false, }, { tag: "latitude", translation: "{0}は正しい緯度の座標を含まなければなりません", override: false, }, { tag: "longitude", translation: "{0}は正しい経度の座標を含まなければなりません", override: false, }, { tag: "ssn", translation: "{0}は正しい社会保障番号でなければなりません", override: false, }, { tag: "ipv4", translation: "{0}は正しいIPv4アドレスでなければなりません", override: false, }, { tag: "ipv6", translation: "{0}は正しいIPv6アドレスでなければなりません", override: false, }, { tag: "ip", translation: "{0}は正しいIPアドレスでなければなりません", override: false, }, { tag: "cidr", translation: "{0}は正しいCIDR表記を含まなければなりません", override: false, }, { tag: "cidrv4", translation: "{0}はIPv4アドレスの正しいCIDR表記を含まなければなりません", override: false, }, { tag: "cidrv6", translation: "{0}はIPv6アドレスの正しいCIDR表記を含まなければなりません", override: false, }, { tag: "tcp_addr", translation: "{0}は正しいTCPアドレスでなければなりません", override: false, }, { tag: "tcp4_addr", translation: "{0}は正しいIPv4のTCPアドレスでなければなりません", override: false, }, { tag: "tcp6_addr", translation: "{0}は正しいIPv6のTCPアドレスでなければなりません", override: false, }, { tag: "udp_addr", translation: "{0}は正しいUDPアドレスでなければなりません", override: false, }, { tag: "udp4_addr", translation: "{0}は正しいIPv4のUDPアドレスでなければなりません", override: false, }, { tag: "udp6_addr", translation: "{0}は正しいIPv6のUDPアドレスでなければなりません", override: false, }, { tag: "ip_addr", translation: "{0}は解決可能なIPアドレスでなければなりません", override: false, }, { tag: "ip4_addr", translation: "{0}は解決可能なIPv4アドレスでなければなりません", override: false, }, { tag: "ip6_addr", translation: "{0}は解決可能なIPv6アドレスでなければなりません", override: false, }, { tag: "unix_addr", translation: "{0}は解決可能なUNIXアドレスでなければなりません", override: false, }, { tag: "mac", translation: "{0}は正しいMACアドレスを含まなければなりません", override: false, }, { tag: "iscolor", translation: "{0}は正しい色でなければなりません", override: false, }, { tag: "oneof", translation: "{0}は[{1}]のうちのいずれかでなければなりません", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { s, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return s }, }, } for _, t := range translations { if t.customTransFunc != nil && t.customRegisFunc != nil { err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, t.customTransFunc) } else if t.customTransFunc != nil && t.customRegisFunc == nil { err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), t.customTransFunc) } else if t.customTransFunc == nil && t.customRegisFunc != nil { err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, translateFunc) } else { err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), translateFunc) } if err != nil { return } } return } func registrationFunc(tag string, translation string, override bool) validator.RegisterTranslationsFunc { return func(ut ut.Translator) (err error) { if err = ut.Add(tag, translation, override); err != nil { return } return } } func translateFunc(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t } validator-10.4.1/translations/ja/ja_test.go000066400000000000000000000505231374261122600206660ustar00rootroot00000000000000package ja import ( "testing" "time" ja_locale "github.com/go-playground/locales/ja" ut "github.com/go-playground/universal-translator" . "github.com/go-playground/assert/v2" "github.com/go-playground/validator/v10" ) func TestTranslations(t *testing.T) { japanese := ja_locale.New() uni := ut.New(japanese, japanese) trans, _ := uni.GetTranslator("ja") validate := validator.New() err := RegisterDefaultTranslations(validate, trans) Equal(t, err, nil) type Inner struct { EqCSFieldString string NeCSFieldString string GtCSFieldString string GteCSFieldString string LtCSFieldString string LteCSFieldString string } type Test struct { Inner Inner RequiredString string `validate:"required"` RequiredNumber int `validate:"required"` RequiredMultiple []string `validate:"required"` LenString string `validate:"len=1"` LenNumber float64 `validate:"len=1113.00"` LenMultiple []string `validate:"len=7"` MinString string `validate:"min=1"` MinNumber float64 `validate:"min=1113.00"` MinMultiple []string `validate:"min=7"` MaxString string `validate:"max=3"` MaxNumber float64 `validate:"max=1113.00"` MaxMultiple []string `validate:"max=7"` EqString string `validate:"eq=3"` EqNumber float64 `validate:"eq=2.33"` EqMultiple []string `validate:"eq=7"` NeString string `validate:"ne="` NeNumber float64 `validate:"ne=0.00"` NeMultiple []string `validate:"ne=0"` LtString string `validate:"lt=3"` LtNumber float64 `validate:"lt=5.56"` LtMultiple []string `validate:"lt=2"` LtTime time.Time `validate:"lt"` LteString string `validate:"lte=3"` LteNumber float64 `validate:"lte=5.56"` LteMultiple []string `validate:"lte=2"` LteTime time.Time `validate:"lte"` GtString string `validate:"gt=3"` GtNumber float64 `validate:"gt=5.56"` GtMultiple []string `validate:"gt=2"` GtTime time.Time `validate:"gt"` GteString string `validate:"gte=3"` GteNumber float64 `validate:"gte=5.56"` GteMultiple []string `validate:"gte=2"` GteTime time.Time `validate:"gte"` EqFieldString string `validate:"eqfield=MaxString"` EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"` NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"` GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"` GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"` LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"` LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"` NeFieldString string `validate:"nefield=EqFieldString"` GtFieldString string `validate:"gtfield=MaxString"` GteFieldString string `validate:"gtefield=MaxString"` LtFieldString string `validate:"ltfield=MaxString"` LteFieldString string `validate:"ltefield=MaxString"` AlphaString string `validate:"alpha"` AlphanumString string `validate:"alphanum"` NumericString string `validate:"numeric"` NumberString string `validate:"number"` HexadecimalString string `validate:"hexadecimal"` HexColorString string `validate:"hexcolor"` RGBColorString string `validate:"rgb"` RGBAColorString string `validate:"rgba"` HSLColorString string `validate:"hsl"` HSLAColorString string `validate:"hsla"` Email string `validate:"email"` URL string `validate:"url"` URI string `validate:"uri"` Base64 string `validate:"base64"` Contains string `validate:"contains=purpose"` ContainsAny string `validate:"containsany=!@#$"` Excludes string `validate:"excludes=text"` ExcludesAll string `validate:"excludesall=!@#$"` ExcludesRune string `validate:"excludesrune=☻"` ISBN string `validate:"isbn"` ISBN10 string `validate:"isbn10"` ISBN13 string `validate:"isbn13"` UUID string `validate:"uuid"` UUID3 string `validate:"uuid3"` UUID4 string `validate:"uuid4"` UUID5 string `validate:"uuid5"` ASCII string `validate:"ascii"` PrintableASCII string `validate:"printascii"` MultiByte string `validate:"multibyte"` DataURI string `validate:"datauri"` Latitude string `validate:"latitude"` Longitude string `validate:"longitude"` SSN string `validate:"ssn"` IP string `validate:"ip"` IPv4 string `validate:"ipv4"` IPv6 string `validate:"ipv6"` CIDR string `validate:"cidr"` CIDRv4 string `validate:"cidrv4"` CIDRv6 string `validate:"cidrv6"` TCPAddr string `validate:"tcp_addr"` TCPAddrv4 string `validate:"tcp4_addr"` TCPAddrv6 string `validate:"tcp6_addr"` UDPAddr string `validate:"udp_addr"` UDPAddrv4 string `validate:"udp4_addr"` UDPAddrv6 string `validate:"udp6_addr"` IPAddr string `validate:"ip_addr"` IPAddrv4 string `validate:"ip4_addr"` IPAddrv6 string `validate:"ip6_addr"` UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future MAC string `validate:"mac"` IsColor string `validate:"iscolor"` StrPtrMinLen *string `validate:"min=10"` StrPtrMaxLen *string `validate:"max=1"` StrPtrLen *string `validate:"len=2"` StrPtrLt *string `validate:"lt=1"` StrPtrLte *string `validate:"lte=1"` StrPtrGt *string `validate:"gt=10"` StrPtrGte *string `validate:"gte=10"` OneOfString string `validate:"oneof=red green"` OneOfInt int `validate:"oneof=5 63"` } var test Test test.Inner.EqCSFieldString = "1234" test.Inner.GtCSFieldString = "1234" test.Inner.GteCSFieldString = "1234" test.MaxString = "1234" test.MaxNumber = 2000 test.MaxMultiple = make([]string, 9) test.LtString = "1234" test.LtNumber = 6 test.LtMultiple = make([]string, 3) test.LtTime = time.Now().Add(time.Hour * 24) test.LteString = "1234" test.LteNumber = 6 test.LteMultiple = make([]string, 3) test.LteTime = time.Now().Add(time.Hour * 24) test.LtFieldString = "12345" test.LteFieldString = "12345" test.LtCSFieldString = "1234" test.LteCSFieldString = "1234" test.AlphaString = "abc3" test.AlphanumString = "abc3!" test.NumericString = "12E.00" test.NumberString = "12E" test.Excludes = "this is some test text" test.ExcludesAll = "This is Great!" test.ExcludesRune = "Love it ☻" test.ASCII = "カタカナ" test.PrintableASCII = "カタカナ" test.MultiByte = "1234feerf" s := "toolong" test.StrPtrMaxLen = &s test.StrPtrLen = &s err = validate.Struct(test) NotEqual(t, err, nil) errs, ok := err.(validator.ValidationErrors) Equal(t, ok, true) tests := []struct { ns string expected string }{ { ns: "Test.IsColor", expected: "IsColorは正しい色でなければなりません", }, { ns: "Test.MAC", expected: "MACは正しいMACアドレスを含まなければなりません", }, { ns: "Test.IPAddr", expected: "IPAddrは解決可能なIPアドレスでなければなりません", }, { ns: "Test.IPAddrv4", expected: "IPAddrv4は解決可能なIPv4アドレスでなければなりません", }, { ns: "Test.IPAddrv6", expected: "IPAddrv6は解決可能なIPv6アドレスでなければなりません", }, { ns: "Test.UDPAddr", expected: "UDPAddrは正しいUDPアドレスでなければなりません", }, { ns: "Test.UDPAddrv4", expected: "UDPAddrv4は正しいIPv4のUDPアドレスでなければなりません", }, { ns: "Test.UDPAddrv6", expected: "UDPAddrv6は正しいIPv6のUDPアドレスでなければなりません", }, { ns: "Test.TCPAddr", expected: "TCPAddrは正しいTCPアドレスでなければなりません", }, { ns: "Test.TCPAddrv4", expected: "TCPAddrv4は正しいIPv4のTCPアドレスでなければなりません", }, { ns: "Test.TCPAddrv6", expected: "TCPAddrv6は正しいIPv6のTCPアドレスでなければなりません", }, { ns: "Test.CIDR", expected: "CIDRは正しいCIDR表記を含まなければなりません", }, { ns: "Test.CIDRv4", expected: "CIDRv4はIPv4アドレスの正しいCIDR表記を含まなければなりません", }, { ns: "Test.CIDRv6", expected: "CIDRv6はIPv6アドレスの正しいCIDR表記を含まなければなりません", }, { ns: "Test.SSN", expected: "SSNは正しい社会保障番号でなければなりません", }, { ns: "Test.IP", expected: "IPは正しいIPアドレスでなければなりません", }, { ns: "Test.IPv4", expected: "IPv4は正しいIPv4アドレスでなければなりません", }, { ns: "Test.IPv6", expected: "IPv6は正しいIPv6アドレスでなければなりません", }, { ns: "Test.DataURI", expected: "DataURIは正しいデータURIを含まなければなりません", }, { ns: "Test.Latitude", expected: "Latitudeは正しい緯度の座標を含まなければなりません", }, { ns: "Test.Longitude", expected: "Longitudeは正しい経度の座標を含まなければなりません", }, { ns: "Test.MultiByte", expected: "MultiByteはマルチバイト文字を含まなければなりません", }, { ns: "Test.ASCII", expected: "ASCIIはASCII文字のみを含まなければなりません", }, { ns: "Test.PrintableASCII", expected: "PrintableASCIIは印刷可能なASCII文字のみを含まなければなりません", }, { ns: "Test.UUID", expected: "UUIDは正しいUUIDでなければなりません", }, { ns: "Test.UUID3", expected: "UUID3はバージョンが3の正しいUUIDでなければなりません", }, { ns: "Test.UUID4", expected: "UUID4はバージョンが4の正しいUUIDでなければなりません", }, { ns: "Test.UUID5", expected: "UUID5はバージョンが4の正しいUUIDでなければなりません", }, { ns: "Test.ISBN", expected: "ISBNは正しいISBN番号でなければなりません", }, { ns: "Test.ISBN10", expected: "ISBN10は正しいISBN-10番号でなければなりません", }, { ns: "Test.ISBN13", expected: "ISBN13は正しいISBN-13番号でなければなりません", }, { ns: "Test.Excludes", expected: "Excludesには'text'というテキストを含むことはできません", }, { ns: "Test.ExcludesAll", expected: "ExcludesAllには'!@#$'のどれも含めることはできません", }, { ns: "Test.ExcludesRune", expected: "ExcludesRuneには'☻'を含めることはできません", }, { ns: "Test.ContainsAny", expected: "ContainsAnyは'!@#$'の少なくとも1つを含まなければなりません", }, { ns: "Test.Contains", expected: "Containsは'purpose'を含まなければなりません", }, { ns: "Test.Base64", expected: "Base64は正しいBase64文字列でなければなりません", }, { ns: "Test.Email", expected: "Emailは正しいメールアドレスでなければなりません", }, { ns: "Test.URL", expected: "URLは正しいURLでなければなりません", }, { ns: "Test.URI", expected: "URIは正しいURIでなければなりません", }, { ns: "Test.RGBColorString", expected: "RGBColorStringは正しいRGBカラーコードでなければなりません", }, { ns: "Test.RGBAColorString", expected: "RGBAColorStringは正しいRGBAカラーコードでなければなりません", }, { ns: "Test.HSLColorString", expected: "HSLColorStringは正しいHSLカラーコードでなければなりません", }, { ns: "Test.HSLAColorString", expected: "HSLAColorStringは正しいHSLAカラーコードでなければなりません", }, { ns: "Test.HexadecimalString", expected: "HexadecimalStringは正しい16進表記でなければなりません", }, { ns: "Test.HexColorString", expected: "HexColorStringは正しいHEXカラーコードでなければなりません", }, { ns: "Test.NumberString", expected: "NumberStringは正しい数でなければなりません", }, { ns: "Test.NumericString", expected: "NumericStringは正しい数字でなければなりません", }, { ns: "Test.AlphanumString", expected: "AlphanumStringはアルファベットと数字のみを含むことができます", }, { ns: "Test.AlphaString", expected: "AlphaStringはアルファベットのみを含むことができます", }, { ns: "Test.LtFieldString", expected: "LtFieldStringはMaxStringよりも小さくなければなりません", }, { ns: "Test.LteFieldString", expected: "LteFieldStringはMaxString以下でなければなりません", }, { ns: "Test.GtFieldString", expected: "GtFieldStringはMaxStringよりも大きくなければなりません", }, { ns: "Test.GteFieldString", expected: "GteFieldStringはMaxString以上でなければなりません", }, { ns: "Test.NeFieldString", expected: "NeFieldStringはEqFieldStringとは異ならなければなりません", }, { ns: "Test.LtCSFieldString", expected: "LtCSFieldStringはInner.LtCSFieldStringよりも小さくなければなりません", }, { ns: "Test.LteCSFieldString", expected: "LteCSFieldStringはInner.LteCSFieldString以下でなければなりません", }, { ns: "Test.GtCSFieldString", expected: "GtCSFieldStringはInner.GtCSFieldStringよりも大きくなければなりません", }, { ns: "Test.GteCSFieldString", expected: "GteCSFieldStringはInner.GteCSFieldString以上でなければなりません", }, { ns: "Test.NeCSFieldString", expected: "NeCSFieldStringはInner.NeCSFieldStringとは異ならなければなりません", }, { ns: "Test.EqCSFieldString", expected: "EqCSFieldStringはInner.EqCSFieldStringと等しくなければなりません", }, { ns: "Test.EqFieldString", expected: "EqFieldStringはMaxStringと等しくなければなりません", }, { ns: "Test.GteString", expected: "GteStringの長さは少なくとも3文字以上はなければなりません", }, { ns: "Test.GteNumber", expected: "GteNumberは5.56かより大きくなければなりません", }, { ns: "Test.GteMultiple", expected: "GteMultipleは少なくとも2つの項目を含まなければなりません", }, { ns: "Test.GteTime", expected: "GteTimeは現時刻以降でなければなりません", }, { ns: "Test.GtString", expected: "GtStringの長さは3文字よりも多くなければなりません", }, { ns: "Test.GtNumber", expected: "GtNumberは5.56よりも大きくなければなりません", }, { ns: "Test.GtMultiple", expected: "GtMultipleは2つの項目よりも多い項目を含まなければなりません", }, { ns: "Test.GtTime", expected: "GtTimeは現時刻よりも後でなければなりません", }, { ns: "Test.LteString", expected: "LteStringの長さは最大でも3文字でなければなりません", }, { ns: "Test.LteNumber", expected: "LteNumberは5.56かより小さくなければなりません", }, { ns: "Test.LteMultiple", expected: "LteMultipleは最大でも2つの項目を含まなければなりません", }, { ns: "Test.LteTime", expected: "LteTimeは現時刻以前でなければなりません", }, { ns: "Test.LtString", expected: "LtStringの長さは3文字よりも少なくなければなりません", }, { ns: "Test.LtNumber", expected: "LtNumberは5.56よりも小さくなければなりません", }, { ns: "Test.LtMultiple", expected: "LtMultipleは2つの項目よりも少ない項目を含まなければなりません", }, { ns: "Test.LtTime", expected: "LtTimeは現時刻よりも前でなければなりません", }, { ns: "Test.NeString", expected: "NeStringはと異ならなければなりません", }, { ns: "Test.NeNumber", expected: "NeNumberは0.00と異ならなければなりません", }, { ns: "Test.NeMultiple", expected: "NeMultipleの項目の数は0個と異ならなければなりません", }, { ns: "Test.EqString", expected: "EqStringは3と等しくありません", }, { ns: "Test.EqNumber", expected: "EqNumberは2.33と等しくありません", }, { ns: "Test.EqMultiple", expected: "EqMultipleは7と等しくありません", }, { ns: "Test.MaxString", expected: "MaxStringの長さは最大でも3文字でなければなりません", }, { ns: "Test.MaxNumber", expected: "MaxNumberは1,113.00かより小さくなければなりません", }, { ns: "Test.MaxMultiple", expected: "MaxMultipleは最大でも7つの項目を含まなければなりません", }, { ns: "Test.MinString", expected: "MinStringの長さは少なくとも1文字はなければなりません", }, { ns: "Test.MinNumber", expected: "MinNumberは1,113.00かより大きくなければなりません", }, { ns: "Test.MinMultiple", expected: "MinMultipleは少なくとも7つの項目を含まなければなりません", }, { ns: "Test.LenString", expected: "LenStringの長さは1文字でなければなりません", }, { ns: "Test.LenNumber", expected: "LenNumberは1,113.00と等しくなければなりません", }, { ns: "Test.LenMultiple", expected: "LenMultipleは7つの項目を含まなければなりません", }, { ns: "Test.RequiredString", expected: "RequiredStringは必須フィールドです", }, { ns: "Test.RequiredNumber", expected: "RequiredNumberは必須フィールドです", }, { ns: "Test.RequiredMultiple", expected: "RequiredMultipleは必須フィールドです", }, { ns: "Test.StrPtrMinLen", expected: "StrPtrMinLenの長さは少なくとも10文字はなければなりません", }, { ns: "Test.StrPtrMaxLen", expected: "StrPtrMaxLenの長さは最大でも1文字でなければなりません", }, { ns: "Test.StrPtrLen", expected: "StrPtrLenの長さは2文字でなければなりません", }, { ns: "Test.StrPtrLt", expected: "StrPtrLtの長さは1文字よりも少なくなければなりません", }, { ns: "Test.StrPtrLte", expected: "StrPtrLteの長さは最大でも1文字でなければなりません", }, { ns: "Test.StrPtrGt", expected: "StrPtrGtの長さは10文字よりも多くなければなりません", }, { ns: "Test.StrPtrGte", expected: "StrPtrGteの長さは少なくとも10文字以上はなければなりません", }, { ns: "Test.OneOfString", expected: "OneOfStringは[red green]のうちのいずれかでなければなりません", }, { ns: "Test.OneOfInt", expected: "OneOfIntは[5 63]のうちのいずれかでなければなりません", }, } for _, tt := range tests { var fe validator.FieldError for _, e := range errs { if tt.ns == e.Namespace() { fe = e break } } NotEqual(t, fe, nil) Equal(t, tt.expected, fe.Translate(trans)) } } validator-10.4.1/translations/nl/000077500000000000000000000000001374261122600167205ustar00rootroot00000000000000validator-10.4.1/translations/nl/nl.go000066400000000000000000000766131374261122600176750ustar00rootroot00000000000000package nl import ( "fmt" "log" "reflect" "strconv" "strings" "time" "github.com/go-playground/locales" ut "github.com/go-playground/universal-translator" "github.com/go-playground/validator/v10" ) // RegisterDefaultTranslations registers a set of default translations // for all built in tag's in validator; you may add your own as desired. func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (err error) { translations := []struct { tag string translation string override bool customRegisFunc validator.RegisterTranslationsFunc customTransFunc validator.TranslationFunc }{ { tag: "required", translation: "{0} is een verplicht veld", override: false, }, { tag: "len", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("len-string", "{0} moet {1} lang zijn", false); err != nil { return } if err = ut.AddCardinal("len-string-character", "{0} karakter", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("len-string-character", "{0} karakters", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("len-number", "{0} moet gelijk zijn aan {1}", false); err != nil { return } if err = ut.Add("len-items", "{0} moet {1} bevatten", false); err != nil { return } if err = ut.AddCardinal("len-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("len-items-item", "{0} items", locales.PluralRuleOther, false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var digits uint64 var kind reflect.Kind if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { goto END } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string c, err = ut.C("len-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("len-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string c, err = ut.C("len-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("len-items", fe.Field(), c) default: t, err = ut.T("len-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "min", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("min-string", "{0} moet tenminste {1} lang zijn", false); err != nil { return } if err = ut.AddCardinal("min-string-character", "{0} karakter", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("min-string-character", "{0} karakters", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("min-number", "{0} moet {1} of groter zijn", false); err != nil { return } if err = ut.Add("min-items", "{0} moet tenminste {1} bevatten", false); err != nil { return } if err = ut.AddCardinal("min-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("min-items-item", "{0} items", locales.PluralRuleOther, false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var digits uint64 var kind reflect.Kind if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { goto END } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string c, err = ut.C("min-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("min-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string c, err = ut.C("min-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("min-items", fe.Field(), c) default: t, err = ut.T("min-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "max", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("max-string", "{0} mag maximaal {1} lang zijn", false); err != nil { return } if err = ut.AddCardinal("max-string-character", "{0} karakter", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("max-string-character", "{0} karakters", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("max-number", "{0} moet {1} of kleiner zijn", false); err != nil { return } if err = ut.Add("max-items", "{0} mag maximaal {1} bevatten", false); err != nil { return } if err = ut.AddCardinal("max-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("max-items-item", "{0} items", locales.PluralRuleOther, false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var digits uint64 var kind reflect.Kind if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { goto END } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string c, err = ut.C("max-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("max-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string c, err = ut.C("max-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("max-items", fe.Field(), c) default: t, err = ut.T("max-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "eq", translation: "{0} is niet gelijk aan {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { fmt.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ne", translation: "{0} mag niet gelijk zijn aan {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { fmt.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "lt", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("lt-string", "{0} moet minder dan {1} lang zijn", false); err != nil { return } if err = ut.AddCardinal("lt-string-character", "{0} karakter", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("lt-string-character", "{0} karakters", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lt-number", "{0} moet kleiner zijn dan {1}", false); err != nil { return } if err = ut.Add("lt-items", "{0} moet minder dan {1} bevatten", false); err != nil { return } if err = ut.AddCardinal("lt-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("lt-items-item", "{0} items", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lt-datetime", "{0} moet kleiner zijn dan de huidige datum & tijd", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("lt-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lt-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("lt-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lt-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) goto END } t, err = ut.T("lt-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("lt-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "lte", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("lte-string", "{0} mag maximaal {1} lang zijn", false); err != nil { return } if err = ut.AddCardinal("lte-string-character", "{0} karakter", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("lte-string-character", "{0} karakters", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lte-number", "{0} moet {1} of minder zijn", false); err != nil { return } if err = ut.Add("lte-items", "{0} mag maximaal {1} bevatten", false); err != nil { return } if err = ut.AddCardinal("lte-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("lte-items-item", "{0} items", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lte-datetime", "{0} moet kleiner dan of gelijk aan de huidige datum & tijd zijn", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("lte-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lte-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("lte-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lte-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) goto END } t, err = ut.T("lte-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("lte-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "gt", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("gt-string", "{0} moet langer dan {1} zijn", false); err != nil { return } if err = ut.AddCardinal("gt-string-character", "{0} karakter", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("gt-string-character", "{0} karakters", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gt-number", "{0} moet groter zijn dan {1}", false); err != nil { return } if err = ut.Add("gt-items", "{0} moet meer dan {1} bevatten", false); err != nil { return } if err = ut.AddCardinal("gt-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("gt-items-item", "{0} items", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gt-datetime", "{0} moet groter zijn dan de huidige datum & tijd", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("gt-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gt-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("gt-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gt-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) goto END } t, err = ut.T("gt-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("gt-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "gte", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("gte-string", "{0} moet tenminste {1} lang zijn", false); err != nil { return } if err = ut.AddCardinal("gte-string-character", "{0} karakter", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("gte-string-character", "{0} karakters", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gte-number", "{0} moet {1} of groter zijn", false); err != nil { return } if err = ut.Add("gte-items", "{0} moet tenminste {1} bevatten", false); err != nil { return } if err = ut.AddCardinal("gte-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("gte-items-item", "{0} items", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gte-datetime", "{0} moet groter dan of gelijk zijn aan de huidige datum & tijd", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("gte-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gte-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("gte-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gte-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) goto END } t, err = ut.T("gte-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("gte-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "eqfield", translation: "{0} moet gelijk zijn aan {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "eqcsfield", translation: "{0} moet gelijk zijn aan {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "necsfield", translation: "{0} mag niet gelijk zijn aan {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtcsfield", translation: "{0} moet groter zijn dan {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtecsfield", translation: "{0} moet groter dan of gelijk aan {1} zijn", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltcsfield", translation: "{0} moet kleiner zijn dan {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltecsfield", translation: "{0} moet kleiner dan of gelijk aan {1} zijn", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "nefield", translation: "{0} mag niet gelijk zijn aan {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtfield", translation: "{0} moet groter zijn dan {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtefield", translation: "{0} moet groter dan of gelijk aan {1} zijn", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltfield", translation: "{0} moet kleiner zijn dan {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltefield", translation: "{0} moet kleiner dan of gelijk aan {1} zijn", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "alpha", translation: "{0} mag alleen alfabetische karakters bevatten", override: false, }, { tag: "alphanum", translation: "{0} mag alleen alfanumerieke karakters bevatten", override: false, }, { tag: "numeric", translation: "{0} moet een geldige numerieke waarde zijn", override: false, }, { tag: "number", translation: "{0} moet een geldig getal zijn", override: false, }, { tag: "hexadecimal", translation: "{0} moet een geldig hexadecimaal getal zijn", override: false, }, { tag: "hexcolor", translation: "{0} moet een geldige HEX kleur zijn", override: false, }, { tag: "rgb", translation: "{0} moet een geldige RGB kleur zijn", override: false, }, { tag: "rgba", translation: "{0} moet een geldige RGBA kleur zijn", override: false, }, { tag: "hsl", translation: "{0} moet een geldige HSL kleur zijn", override: false, }, { tag: "hsla", translation: "{0} moet een geldige HSLA kleur zijn", override: false, }, { tag: "email", translation: "{0} moet een geldig email adres zijn", override: false, }, { tag: "url", translation: "{0} moet een geldige URL zijn", override: false, }, { tag: "uri", translation: "{0} moet een geldige URI zijn", override: false, }, { tag: "base64", translation: "{0} moet een geldige Base64 string zijn", override: false, }, { tag: "contains", translation: "{0} moet de tekst '{1}' bevatten", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "containsany", translation: "{0} moet tenminste een van de volgende karakters bevatten '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "excludes", translation: "{0} mag niet de tekst '{1}' bevatten", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "excludesall", translation: "{0} mag niet een van de volgende karakters bevatten '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "excludesrune", translation: "{0} mag niet het volgende bevatten '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "isbn", translation: "{0} moet een geldig ISBN nummer zijn", override: false, }, { tag: "isbn10", translation: "{0} moet een geldig ISBN-10 nummer zijn", override: false, }, { tag: "isbn13", translation: "{0} moet een geldig ISBN-13 nummer zijn", override: false, }, { tag: "uuid", translation: "{0} moet een geldige UUID zijn", override: false, }, { tag: "uuid3", translation: "{0} moet een geldige versie 3 UUID zijn", override: false, }, { tag: "uuid4", translation: "{0} moet een geldige versie 4 UUID zijn", override: false, }, { tag: "uuid5", translation: "{0} moet een geldige versie 5 UUID zijn", override: false, }, { tag: "ascii", translation: "{0} mag alleen ascii karakters bevatten", override: false, }, { tag: "printascii", translation: "{0} mag alleen afdrukbare ascii karakters bevatten", override: false, }, { tag: "multibyte", translation: "{0} moet multibyte karakters bevatten", override: false, }, { tag: "datauri", translation: "{0} moet een geldige Data URI bevatten", override: false, }, { tag: "latitude", translation: "{0} moet geldige breedtegraadcoördinaten bevatten", override: false, }, { tag: "longitude", translation: "{0} moet geldige lengtegraadcoördinaten bevatten", override: false, }, { tag: "ssn", translation: "{0} moet een geldig SSN nummer zijn", override: false, }, { tag: "ipv4", translation: "{0} moet een geldig IPv4 adres zijn", override: false, }, { tag: "ipv6", translation: "{0} moet een geldig IPv6 adres zijn", override: false, }, { tag: "ip", translation: "{0} moet een geldig IP adres zijn", override: false, }, { tag: "cidr", translation: "{0} moet een geldige CIDR notatie bevatten", override: false, }, { tag: "cidrv4", translation: "{0} moet een geldige CIDR notatie voor een IPv4 adres bevatten", override: false, }, { tag: "cidrv6", translation: "{0} moet een geldige CIDR notatie voor een IPv6 adres bevatten", override: false, }, { tag: "tcp_addr", translation: "{0} moet een geldig TCP adres zijn", override: false, }, { tag: "tcp4_addr", translation: "{0} moet een geldig IPv4 TCP adres zijn", override: false, }, { tag: "tcp6_addr", translation: "{0} moet een geldig IPv6 TCP adres zijn", override: false, }, { tag: "udp_addr", translation: "{0} moet een geldig UDP adres zijn", override: false, }, { tag: "udp4_addr", translation: "{0} moet een geldig IPv4 UDP adres zijn", override: false, }, { tag: "udp6_addr", translation: "{0} moet een geldig IPv6 UDP adres zijn", override: false, }, { tag: "ip_addr", translation: "{0} moet een oplosbaar IP adres zijn", override: false, }, { tag: "ip4_addr", translation: "{0} moet een oplosbaar IPv4 adres zijn", override: false, }, { tag: "ip6_addr", translation: "{0} moet een oplosbaar IPv6 adres zijn", override: false, }, { tag: "unix_addr", translation: "{0} moet een oplosbaar UNIX adres zijn", override: false, }, { tag: "mac", translation: "{0} moet een geldig MAC adres bevatten", override: false, }, { tag: "iscolor", translation: "{0} moet een geldige kleur zijn", override: false, }, { tag: "oneof", translation: "{0} moet een van de volgende zijn [{1}]", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { s, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return s }, }, } for _, t := range translations { if t.customTransFunc != nil && t.customRegisFunc != nil { err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, t.customTransFunc) } else if t.customTransFunc != nil && t.customRegisFunc == nil { err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), t.customTransFunc) } else if t.customTransFunc == nil && t.customRegisFunc != nil { err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, translateFunc) } else { err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), translateFunc) } if err != nil { return } } return } func registrationFunc(tag string, translation string, override bool) validator.RegisterTranslationsFunc { return func(ut ut.Translator) (err error) { if err = ut.Add(tag, translation, override); err != nil { return } return } } func translateFunc(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t } validator-10.4.1/translations/nl/nl_test.go000066400000000000000000000440611374261122600207240ustar00rootroot00000000000000package nl import ( "testing" "time" english "github.com/go-playground/locales/en" ut "github.com/go-playground/universal-translator" . "github.com/go-playground/assert/v2" "github.com/go-playground/validator/v10" ) func TestTranslations(t *testing.T) { eng := english.New() uni := ut.New(eng, eng) trans, _ := uni.GetTranslator("en") validate := validator.New() err := RegisterDefaultTranslations(validate, trans) Equal(t, err, nil) type Inner struct { EqCSFieldString string NeCSFieldString string GtCSFieldString string GteCSFieldString string LtCSFieldString string LteCSFieldString string } type Test struct { Inner Inner RequiredString string `validate:"required"` RequiredNumber int `validate:"required"` RequiredMultiple []string `validate:"required"` LenString string `validate:"len=1"` LenNumber float64 `validate:"len=1113.00"` LenMultiple []string `validate:"len=7"` MinString string `validate:"min=1"` MinNumber float64 `validate:"min=1113.00"` MinMultiple []string `validate:"min=7"` MaxString string `validate:"max=3"` MaxNumber float64 `validate:"max=1113.00"` MaxMultiple []string `validate:"max=7"` EqString string `validate:"eq=3"` EqNumber float64 `validate:"eq=2.33"` EqMultiple []string `validate:"eq=7"` NeString string `validate:"ne="` NeNumber float64 `validate:"ne=0.00"` NeMultiple []string `validate:"ne=0"` LtString string `validate:"lt=3"` LtNumber float64 `validate:"lt=5.56"` LtMultiple []string `validate:"lt=2"` LtTime time.Time `validate:"lt"` LteString string `validate:"lte=3"` LteNumber float64 `validate:"lte=5.56"` LteMultiple []string `validate:"lte=2"` LteTime time.Time `validate:"lte"` GtString string `validate:"gt=3"` GtNumber float64 `validate:"gt=5.56"` GtMultiple []string `validate:"gt=2"` GtTime time.Time `validate:"gt"` GteString string `validate:"gte=3"` GteNumber float64 `validate:"gte=5.56"` GteMultiple []string `validate:"gte=2"` GteTime time.Time `validate:"gte"` EqFieldString string `validate:"eqfield=MaxString"` EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"` NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"` GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"` GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"` LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"` LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"` NeFieldString string `validate:"nefield=EqFieldString"` GtFieldString string `validate:"gtfield=MaxString"` GteFieldString string `validate:"gtefield=MaxString"` LtFieldString string `validate:"ltfield=MaxString"` LteFieldString string `validate:"ltefield=MaxString"` AlphaString string `validate:"alpha"` AlphanumString string `validate:"alphanum"` NumericString string `validate:"numeric"` NumberString string `validate:"number"` HexadecimalString string `validate:"hexadecimal"` HexColorString string `validate:"hexcolor"` RGBColorString string `validate:"rgb"` RGBAColorString string `validate:"rgba"` HSLColorString string `validate:"hsl"` HSLAColorString string `validate:"hsla"` Email string `validate:"email"` URL string `validate:"url"` URI string `validate:"uri"` Base64 string `validate:"base64"` Contains string `validate:"contains=purpose"` ContainsAny string `validate:"containsany=!@#$"` Excludes string `validate:"excludes=text"` ExcludesAll string `validate:"excludesall=!@#$"` ExcludesRune string `validate:"excludesrune=☻"` ISBN string `validate:"isbn"` ISBN10 string `validate:"isbn10"` ISBN13 string `validate:"isbn13"` UUID string `validate:"uuid"` UUID3 string `validate:"uuid3"` UUID4 string `validate:"uuid4"` UUID5 string `validate:"uuid5"` ASCII string `validate:"ascii"` PrintableASCII string `validate:"printascii"` MultiByte string `validate:"multibyte"` DataURI string `validate:"datauri"` Latitude string `validate:"latitude"` Longitude string `validate:"longitude"` SSN string `validate:"ssn"` IP string `validate:"ip"` IPv4 string `validate:"ipv4"` IPv6 string `validate:"ipv6"` CIDR string `validate:"cidr"` CIDRv4 string `validate:"cidrv4"` CIDRv6 string `validate:"cidrv6"` TCPAddr string `validate:"tcp_addr"` TCPAddrv4 string `validate:"tcp4_addr"` TCPAddrv6 string `validate:"tcp6_addr"` UDPAddr string `validate:"udp_addr"` UDPAddrv4 string `validate:"udp4_addr"` UDPAddrv6 string `validate:"udp6_addr"` IPAddr string `validate:"ip_addr"` IPAddrv4 string `validate:"ip4_addr"` IPAddrv6 string `validate:"ip6_addr"` UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future MAC string `validate:"mac"` IsColor string `validate:"iscolor"` StrPtrMinLen *string `validate:"min=10"` StrPtrMaxLen *string `validate:"max=1"` StrPtrLen *string `validate:"len=2"` StrPtrLt *string `validate:"lt=1"` StrPtrLte *string `validate:"lte=1"` StrPtrGt *string `validate:"gt=10"` StrPtrGte *string `validate:"gte=10"` OneOfString string `validate:"oneof=red green"` OneOfInt int `validate:"oneof=5 63"` } var test Test test.Inner.EqCSFieldString = "1234" test.Inner.GtCSFieldString = "1234" test.Inner.GteCSFieldString = "1234" test.MaxString = "1234" test.MaxNumber = 2000 test.MaxMultiple = make([]string, 9) test.LtString = "1234" test.LtNumber = 6 test.LtMultiple = make([]string, 3) test.LtTime = time.Now().Add(time.Hour * 24) test.LteString = "1234" test.LteNumber = 6 test.LteMultiple = make([]string, 3) test.LteTime = time.Now().Add(time.Hour * 24) test.LtFieldString = "12345" test.LteFieldString = "12345" test.LtCSFieldString = "1234" test.LteCSFieldString = "1234" test.AlphaString = "abc3" test.AlphanumString = "abc3!" test.NumericString = "12E.00" test.NumberString = "12E" test.Excludes = "this is some test text" test.ExcludesAll = "This is Great!" test.ExcludesRune = "Love it ☻" test.ASCII = "カタカナ" test.PrintableASCII = "カタカナ" test.MultiByte = "1234feerf" s := "toolong" test.StrPtrMaxLen = &s test.StrPtrLen = &s err = validate.Struct(test) NotEqual(t, err, nil) errs, ok := err.(validator.ValidationErrors) Equal(t, ok, true) tests := []struct { ns string expected string }{ { ns: "Test.IsColor", expected: "IsColor moet een geldige kleur zijn", }, { ns: "Test.MAC", expected: "MAC moet een geldig MAC adres bevatten", }, { ns: "Test.IPAddr", expected: "IPAddr moet een oplosbaar IP adres zijn", }, { ns: "Test.IPAddrv4", expected: "IPAddrv4 moet een oplosbaar IPv4 adres zijn", }, { ns: "Test.IPAddrv6", expected: "IPAddrv6 moet een oplosbaar IPv6 adres zijn", }, { ns: "Test.UDPAddr", expected: "UDPAddr moet een geldig UDP adres zijn", }, { ns: "Test.UDPAddrv4", expected: "UDPAddrv4 moet een geldig IPv4 UDP adres zijn", }, { ns: "Test.UDPAddrv6", expected: "UDPAddrv6 moet een geldig IPv6 UDP adres zijn", }, { ns: "Test.TCPAddr", expected: "TCPAddr moet een geldig TCP adres zijn", }, { ns: "Test.TCPAddrv4", expected: "TCPAddrv4 moet een geldig IPv4 TCP adres zijn", }, { ns: "Test.TCPAddrv6", expected: "TCPAddrv6 moet een geldig IPv6 TCP adres zijn", }, { ns: "Test.CIDR", expected: "CIDR moet een geldige CIDR notatie bevatten", }, { ns: "Test.CIDRv4", expected: "CIDRv4 moet een geldige CIDR notatie voor een IPv4 adres bevatten", }, { ns: "Test.CIDRv6", expected: "CIDRv6 moet een geldige CIDR notatie voor een IPv6 adres bevatten", }, { ns: "Test.SSN", expected: "SSN moet een geldig SSN nummer zijn", }, { ns: "Test.IP", expected: "IP moet een geldig IP adres zijn", }, { ns: "Test.IPv4", expected: "IPv4 moet een geldig IPv4 adres zijn", }, { ns: "Test.IPv6", expected: "IPv6 moet een geldig IPv6 adres zijn", }, { ns: "Test.DataURI", expected: "DataURI moet een geldige Data URI bevatten", }, { ns: "Test.Latitude", expected: "Latitude moet geldige breedtegraadcoördinaten bevatten", }, { ns: "Test.Longitude", expected: "Longitude moet geldige lengtegraadcoördinaten bevatten", }, { ns: "Test.MultiByte", expected: "MultiByte moet multibyte karakters bevatten", }, { ns: "Test.ASCII", expected: "ASCII mag alleen ascii karakters bevatten", }, { ns: "Test.PrintableASCII", expected: "PrintableASCII mag alleen afdrukbare ascii karakters bevatten", }, { ns: "Test.UUID", expected: "UUID moet een geldige UUID zijn", }, { ns: "Test.UUID3", expected: "UUID3 moet een geldige versie 3 UUID zijn", }, { ns: "Test.UUID4", expected: "UUID4 moet een geldige versie 4 UUID zijn", }, { ns: "Test.UUID5", expected: "UUID5 moet een geldige versie 5 UUID zijn", }, { ns: "Test.ISBN", expected: "ISBN moet een geldig ISBN nummer zijn", }, { ns: "Test.ISBN10", expected: "ISBN10 moet een geldig ISBN-10 nummer zijn", }, { ns: "Test.ISBN13", expected: "ISBN13 moet een geldig ISBN-13 nummer zijn", }, { ns: "Test.Excludes", expected: "Excludes mag niet de tekst 'text' bevatten", }, { ns: "Test.ExcludesAll", expected: "ExcludesAll mag niet een van de volgende karakters bevatten '!@#$'", }, { ns: "Test.ExcludesRune", expected: "ExcludesRune mag niet het volgende bevatten '☻'", }, { ns: "Test.ContainsAny", expected: "ContainsAny moet tenminste een van de volgende karakters bevatten '!@#$'", }, { ns: "Test.Contains", expected: "Contains moet de tekst 'purpose' bevatten", }, { ns: "Test.Base64", expected: "Base64 moet een geldige Base64 string zijn", }, { ns: "Test.Email", expected: "Email moet een geldig email adres zijn", }, { ns: "Test.URL", expected: "URL moet een geldige URL zijn", }, { ns: "Test.URI", expected: "URI moet een geldige URI zijn", }, { ns: "Test.RGBColorString", expected: "RGBColorString moet een geldige RGB kleur zijn", }, { ns: "Test.RGBAColorString", expected: "RGBAColorString moet een geldige RGBA kleur zijn", }, { ns: "Test.HSLColorString", expected: "HSLColorString moet een geldige HSL kleur zijn", }, { ns: "Test.HSLAColorString", expected: "HSLAColorString moet een geldige HSLA kleur zijn", }, { ns: "Test.HexadecimalString", expected: "HexadecimalString moet een geldig hexadecimaal getal zijn", }, { ns: "Test.HexColorString", expected: "HexColorString moet een geldige HEX kleur zijn", }, { ns: "Test.NumberString", expected: "NumberString moet een geldig getal zijn", }, { ns: "Test.NumericString", expected: "NumericString moet een geldige numerieke waarde zijn", }, { ns: "Test.AlphanumString", expected: "AlphanumString mag alleen alfanumerieke karakters bevatten", }, { ns: "Test.AlphaString", expected: "AlphaString mag alleen alfabetische karakters bevatten", }, { ns: "Test.LtFieldString", expected: "LtFieldString moet kleiner zijn dan MaxString", }, { ns: "Test.LteFieldString", expected: "LteFieldString moet kleiner dan of gelijk aan MaxString zijn", }, { ns: "Test.GtFieldString", expected: "GtFieldString moet groter zijn dan MaxString", }, { ns: "Test.GteFieldString", expected: "GteFieldString moet groter dan of gelijk aan MaxString zijn", }, { ns: "Test.NeFieldString", expected: "NeFieldString mag niet gelijk zijn aan EqFieldString", }, { ns: "Test.LtCSFieldString", expected: "LtCSFieldString moet kleiner zijn dan Inner.LtCSFieldString", }, { ns: "Test.LteCSFieldString", expected: "LteCSFieldString moet kleiner dan of gelijk aan Inner.LteCSFieldString zijn", }, { ns: "Test.GtCSFieldString", expected: "GtCSFieldString moet groter zijn dan Inner.GtCSFieldString", }, { ns: "Test.GteCSFieldString", expected: "GteCSFieldString moet groter dan of gelijk aan Inner.GteCSFieldString zijn", }, { ns: "Test.NeCSFieldString", expected: "NeCSFieldString mag niet gelijk zijn aan Inner.NeCSFieldString", }, { ns: "Test.EqCSFieldString", expected: "EqCSFieldString moet gelijk zijn aan Inner.EqCSFieldString", }, { ns: "Test.EqFieldString", expected: "EqFieldString moet gelijk zijn aan MaxString", }, { ns: "Test.GteString", expected: "GteString moet tenminste 3 karakters lang zijn", }, { ns: "Test.GteNumber", expected: "GteNumber moet 5.56 of groter zijn", }, { ns: "Test.GteMultiple", expected: "GteMultiple moet tenminste 2 items bevatten", }, { ns: "Test.GteTime", expected: "GteTime moet groter dan of gelijk zijn aan de huidige datum & tijd", }, { ns: "Test.GtString", expected: "GtString moet langer dan 3 karakters zijn", }, { ns: "Test.GtNumber", expected: "GtNumber moet groter zijn dan 5.56", }, { ns: "Test.GtMultiple", expected: "GtMultiple moet meer dan 2 items bevatten", }, { ns: "Test.GtTime", expected: "GtTime moet groter zijn dan de huidige datum & tijd", }, { ns: "Test.LteString", expected: "LteString mag maximaal 3 karakters lang zijn", }, { ns: "Test.LteNumber", expected: "LteNumber moet 5.56 of minder zijn", }, { ns: "Test.LteMultiple", expected: "LteMultiple mag maximaal 2 items bevatten", }, { ns: "Test.LteTime", expected: "LteTime moet kleiner dan of gelijk aan de huidige datum & tijd zijn", }, { ns: "Test.LtString", expected: "LtString moet minder dan 3 karakters lang zijn", }, { ns: "Test.LtNumber", expected: "LtNumber moet kleiner zijn dan 5.56", }, { ns: "Test.LtMultiple", expected: "LtMultiple moet minder dan 2 items bevatten", }, { ns: "Test.LtTime", expected: "LtTime moet kleiner zijn dan de huidige datum & tijd", }, { ns: "Test.NeString", expected: "NeString mag niet gelijk zijn aan ", }, { ns: "Test.NeNumber", expected: "NeNumber mag niet gelijk zijn aan 0.00", }, { ns: "Test.NeMultiple", expected: "NeMultiple mag niet gelijk zijn aan 0", }, { ns: "Test.EqString", expected: "EqString is niet gelijk aan 3", }, { ns: "Test.EqNumber", expected: "EqNumber is niet gelijk aan 2.33", }, { ns: "Test.EqMultiple", expected: "EqMultiple is niet gelijk aan 7", }, { ns: "Test.MaxString", expected: "MaxString mag maximaal 3 karakters lang zijn", }, { ns: "Test.MaxNumber", expected: "MaxNumber moet 1,113.00 of kleiner zijn", }, { ns: "Test.MaxMultiple", expected: "MaxMultiple mag maximaal 7 items bevatten", }, { ns: "Test.MinString", expected: "MinString moet tenminste 1 karakter lang zijn", }, { ns: "Test.MinNumber", expected: "MinNumber moet 1,113.00 of groter zijn", }, { ns: "Test.MinMultiple", expected: "MinMultiple moet tenminste 7 items bevatten", }, { ns: "Test.LenString", expected: "LenString moet 1 karakter lang zijn", }, { ns: "Test.LenNumber", expected: "LenNumber moet gelijk zijn aan 1,113.00", }, { ns: "Test.LenMultiple", expected: "LenMultiple moet 7 items bevatten", }, { ns: "Test.RequiredString", expected: "RequiredString is een verplicht veld", }, { ns: "Test.RequiredNumber", expected: "RequiredNumber is een verplicht veld", }, { ns: "Test.RequiredMultiple", expected: "RequiredMultiple is een verplicht veld", }, { ns: "Test.StrPtrMinLen", expected: "StrPtrMinLen moet tenminste 10 karakters lang zijn", }, { ns: "Test.StrPtrMaxLen", expected: "StrPtrMaxLen mag maximaal 1 karakter lang zijn", }, { ns: "Test.StrPtrLen", expected: "StrPtrLen moet 2 karakters lang zijn", }, { ns: "Test.StrPtrLt", expected: "StrPtrLt moet minder dan 1 karakter lang zijn", }, { ns: "Test.StrPtrLte", expected: "StrPtrLte mag maximaal 1 karakter lang zijn", }, { ns: "Test.StrPtrGt", expected: "StrPtrGt moet langer dan 10 karakters zijn", }, { ns: "Test.StrPtrGte", expected: "StrPtrGte moet tenminste 10 karakters lang zijn", }, { ns: "Test.OneOfString", expected: "OneOfString moet een van de volgende zijn [red green]", }, { ns: "Test.OneOfInt", expected: "OneOfInt moet een van de volgende zijn [5 63]", }, } for _, tt := range tests { var fe validator.FieldError for _, e := range errs { if tt.ns == e.Namespace() { fe = e break } } NotEqual(t, fe, nil) Equal(t, tt.expected, fe.Translate(trans)) } } validator-10.4.1/translations/pt/000077500000000000000000000000001374261122600167325ustar00rootroot00000000000000validator-10.4.1/translations/pt/pt.go000066400000000000000000001002471374261122600177100ustar00rootroot00000000000000package pt import ( "fmt" "log" "reflect" "strconv" "strings" "time" "github.com/go-playground/locales" ut "github.com/go-playground/universal-translator" "github.com/go-playground/validator/v10" ) // RegisterDefaultTranslations registers a set of default translations // for all built in tag's in validator; you may add your own as desired. func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (err error) { translations := []struct { tag string translation string override bool customRegisFunc validator.RegisterTranslationsFunc customTransFunc validator.TranslationFunc }{ { tag: "required", translation: "{0} é obrigatório", override: false, }, { tag: "len", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("len-string", "{0} deve ter {1}", false); err != nil { return } if err = ut.AddCardinal("len-string-character", "{0} caractere", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("len-string-character", "{0} caracteres", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("len-number", "{0} deve ser igual a {1}", false); err != nil { return } if err = ut.Add("len-items", "{0} deve conter {1}", false); err != nil { return } if err = ut.AddCardinal("len-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("len-items-item", "{0} items", locales.PluralRuleOther, false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var digits uint64 var kind reflect.Kind if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { goto END } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string c, err = ut.C("len-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("len-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string c, err = ut.C("len-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("len-items", fe.Field(), c) default: t, err = ut.T("len-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "min", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("min-string", "{0} deve ter pelo menos {1}", false); err != nil { return } if err = ut.AddCardinal("min-string-character", "{0} caractere", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("min-string-character", "{0} caracteres", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("min-number", "{0} deve ser {1} ou superior", false); err != nil { return } if err = ut.Add("min-items", "{0} deve conter pelo menos {1}", false); err != nil { return } if err = ut.AddCardinal("min-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("min-items-item", "{0} items", locales.PluralRuleOther, false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var digits uint64 var kind reflect.Kind if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { goto END } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string c, err = ut.C("min-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("min-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string c, err = ut.C("min-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("min-items", fe.Field(), c) default: t, err = ut.T("min-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "max", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("max-string", "{0} deve ter no máximo {1}", false); err != nil { return } if err = ut.AddCardinal("max-string-character", "{0} caractere", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("max-string-character", "{0} caracteres", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("max-number", "{0} deve ser {1} ou menos", false); err != nil { return } if err = ut.Add("max-items", "{0} deve conter no máximo {1}", false); err != nil { return } if err = ut.AddCardinal("max-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("max-items-item", "{0} items", locales.PluralRuleOther, false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var digits uint64 var kind reflect.Kind if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { goto END } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string c, err = ut.C("max-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("max-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string c, err = ut.C("max-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("max-items", fe.Field(), c) default: t, err = ut.T("max-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "eq", translation: "{0} não é igual a {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { fmt.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ne", translation: "{0} não deve ser igual a {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { fmt.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "lt", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("lt-string", "{0} deve ter menos de {1}", false); err != nil { return } if err = ut.AddCardinal("lt-string-character", "{0} caractere", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("lt-string-character", "{0} caracteres", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lt-number", "{0} deve ser menor que {1}", false); err != nil { return } if err = ut.Add("lt-items", "{0} deve conter menos de {1}", false); err != nil { return } if err = ut.AddCardinal("lt-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("lt-items-item", "{0} items", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lt-datetime", "{0} deve ser anterior à data / hora atual", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("lt-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lt-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("lt-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lt-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) goto END } t, err = ut.T("lt-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("lt-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "lte", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("lte-string", "{0} deve ter no máximo {1}", false); err != nil { return } if err = ut.AddCardinal("lte-string-character", "{0} caractere", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("lte-string-character", "{0} caracteres", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lte-number", "{0} deve ser menor ou igual a {1}", false); err != nil { return } if err = ut.Add("lte-items", "{0} deve conter no máximo {1}", false); err != nil { return } if err = ut.AddCardinal("lte-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("lte-items-item", "{0} items", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lte-datetime", "{0} deve ser anterior ou igual à data/hora atual", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("lte-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lte-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("lte-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lte-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) goto END } t, err = ut.T("lte-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("lte-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "gt", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("gt-string", "{0} deve conter mais de {1}", false); err != nil { return } if err = ut.AddCardinal("gt-string-character", "{0} caractere", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("gt-string-character", "{0} caracteres", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gt-number", "{0} deve ser maior que {1}", false); err != nil { return } if err = ut.Add("gt-items", "{0} deve conter mais de {1}", false); err != nil { return } if err = ut.AddCardinal("gt-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("gt-items-item", "{0} items", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gt-datetime", "{0} deve ser posterior à data/hora atual", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("gt-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gt-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("gt-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gt-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) goto END } t, err = ut.T("gt-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("gt-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "gte", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("gte-string", "{0} deve ter pelo menos {1}", false); err != nil { return } if err = ut.AddCardinal("gte-string-character", "{0} caractere", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("gte-string-character", "{0} caracteres", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gte-number", "{0} deve ser maior ou igual a {1}", false); err != nil { return } if err = ut.Add("gte-items", "{0} deve conter pelo menos {1}", false); err != nil { return } if err = ut.AddCardinal("gte-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("gte-items-item", "{0} items", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gte-datetime", "{0} deve ser posterior ou igual à data/hora atual", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("gte-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gte-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("gte-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gte-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) goto END } t, err = ut.T("gte-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("gte-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "eqfield", translation: "{0} deve ser igual a {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "eqcsfield", translation: "{0} deve ser igual a {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "necsfield", translation: "{0} não deve ser igual a {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtcsfield", translation: "{0} deve ser maior que {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtecsfield", translation: "{0} deve ser maior ou igual que {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltcsfield", translation: "{0} deve ser menor que {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltecsfield", translation: "{0} deve ser menor ou igual que {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "nefield", translation: "{0} não deve ser igual a {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtfield", translation: "{0} deve ser maior que {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtefield", translation: "{0} deve ser maior ou igual que {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltfield", translation: "{0} deve ser menor que {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltefield", translation: "{0} deve ser menor ou igual que {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "alpha", translation: "{0} deve conter apenas caracteres alfabéticos", override: false, }, { tag: "alphanum", translation: "{0} deve conter apenas caracteres alfanuméricos", override: false, }, { tag: "numeric", translation: "{0} deve ser um valor numérico válido", override: false, }, { tag: "number", translation: "{0} deve ser um número válido", override: false, }, { tag: "hexadecimal", translation: "{0} deve ser um hexadecimal válido", override: false, }, { tag: "hexcolor", translation: "{0} deve ser uma cor HEX válida", override: false, }, { tag: "rgb", translation: "{0} deve ser uma cor RGB válida", override: false, }, { tag: "rgba", translation: "{0} deve ser uma cor RGBA válida", override: false, }, { tag: "hsl", translation: "{0} deve ser uma cor HSL válida", override: false, }, { tag: "hsla", translation: "{0} deve ser uma cor HSLA válida", override: false, }, { tag: "e164", translation: "{0} deve ser um número de telefone válido no formato E.164", override: false, }, { tag: "email", translation: "{0} deve ser um endereço de e-mail válido", override: false, }, { tag: "url", translation: "{0} deve ser um URL válido", override: false, }, { tag: "uri", translation: "{0} deve ser um URI válido", override: false, }, { tag: "base64", translation: "{0} deve ser uma string Base64 válida", override: false, }, { tag: "contains", translation: "{0} deve conter o texto '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "containsany", translation: "{0} deve conter pelo menos um dos seguintes caracteres '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "excludes", translation: "{0} não deve conter o texto '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "excludesall", translation: "{0} não deve conter os seguintes caracteres '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "excludesrune", translation: "{0} não pode conter o seguinte '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "isbn", translation: "{0} deve ser um número de ISBN válido", override: false, }, { tag: "isbn10", translation: "{0} deve ser um número ISBN-10 válido", override: false, }, { tag: "isbn13", translation: "{0} deve ser um número ISBN-13 válido", override: false, }, { tag: "uuid", translation: "{0} deve ser um UUID válido", override: false, }, { tag: "uuid3", translation: "{0} deve ser um UUID versão 3 válido", override: false, }, { tag: "uuid4", translation: "{0} deve ser um UUID versão 4 válido", override: false, }, { tag: "uuid5", translation: "{0} deve ser um UUID versão 5 válido", override: false, }, { tag: "ascii", translation: "{0} deve conter apenas caracteres ascii", override: false, }, { tag: "printascii", translation: "{0} deve conter apenas caracteres ascii imprimíveis", override: false, }, { tag: "multibyte", translation: "{0} deve conter caracteres multibyte", override: false, }, { tag: "datauri", translation: "{0} deve conter um Data URI válido", override: false, }, { tag: "latitude", translation: "{0} deve conter uma coordenada de latitude válida", override: false, }, { tag: "longitude", translation: "{0} deve conter uma coordenada de longitude válida", override: false, }, { tag: "ssn", translation: "{0} deve ser um número SSN válido", override: false, }, { tag: "ipv4", translation: "{0} deve ser um endereço IPv4 válido", override: false, }, { tag: "ipv6", translation: "{0} deve ser um endereço IPv6 válido", override: false, }, { tag: "ip", translation: "{0} deve ser um endereço IP válido", override: false, }, { tag: "cidr", translation: "{0} não respeita a notação CIDR", override: false, }, { tag: "cidrv4", translation: "{0} não respeita a notação CIDR para um endereço IPv4", override: false, }, { tag: "cidrv6", translation: "{0} não respeita a notação CIDR para um endereço IPv6", override: false, }, { tag: "tcp_addr", translation: "{0} deve ser um endereço TCP válido", override: false, }, { tag: "tcp4_addr", translation: "{0} deve ser um endereço TCP IPv4 válido", override: false, }, { tag: "tcp6_addr", translation: "{0} deve ser um endereço TCP IPv6 válido", override: false, }, { tag: "udp_addr", translation: "{0} deve ser um endereço UDP válido", override: false, }, { tag: "udp4_addr", translation: "{0} deve ser um endereço UDP IPv4 válido", override: false, }, { tag: "udp6_addr", translation: "{0} deve ser um endereço UDP IPv6 válido", override: false, }, { tag: "ip_addr", translation: "{0} deve ser um endereço IP resolvível", override: false, }, { tag: "ip4_addr", translation: "{0} deve ser um endereço IPv4 resolvível", override: false, }, { tag: "ip6_addr", translation: "{0} deve ser um endereço IPv6 resolvível", override: false, }, { tag: "unix_addr", translation: "{0} deve ser um endereço UNIX resolvível", override: false, }, { tag: "mac", translation: "{0} deve conter um endereço MAC válido", override: false, }, { tag: "unique", translation: "{0} deve conter valores únicos", override: false, }, { tag: "iscolor", translation: "{0} deve ser uma cor válida", override: false, }, { tag: "oneof", translation: "{0} deve ser um de [{1}]", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { s, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return s }, }, { tag: "json", translation: "{0} deve ser uma string json válida", override: false, }, { tag: "lowercase", translation: "{0} deve estar em minuscúlas", override: false, }, { tag: "uppercase", translation: "{0} deve estar em maiúsculas", override: false, }, { tag: "datetime", translation: "{0} não está no formato {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, } for _, t := range translations { if t.customTransFunc != nil && t.customRegisFunc != nil { err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, t.customTransFunc) } else if t.customTransFunc != nil && t.customRegisFunc == nil { err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), t.customTransFunc) } else if t.customTransFunc == nil && t.customRegisFunc != nil { err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, translateFunc) } else { err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), translateFunc) } if err != nil { return } } return } func registrationFunc(tag string, translation string, override bool) validator.RegisterTranslationsFunc { return func(ut ut.Translator) (err error) { if err = ut.Add(tag, translation, override); err != nil { return } return } } func translateFunc(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t } validator-10.4.1/translations/pt/pt_test.go000066400000000000000000000476711374261122600207620ustar00rootroot00000000000000package pt import ( "testing" "time" . "github.com/go-playground/assert/v2" "github.com/go-playground/locales/pt" ut "github.com/go-playground/universal-translator" "github.com/go-playground/validator/v10" ) func TestTranslations(t *testing.T) { pt := pt.New() uni := ut.New(pt, pt) trans, _ := uni.GetTranslator("pt") validate := validator.New() err := RegisterDefaultTranslations(validate, trans) Equal(t, err, nil) type Inner struct { EqCSFieldString string NeCSFieldString string GtCSFieldString string GteCSFieldString string LtCSFieldString string LteCSFieldString string } type Test struct { Inner Inner RequiredString string `validate:"required"` RequiredNumber int `validate:"required"` RequiredMultiple []string `validate:"required"` LenString string `validate:"len=1"` LenNumber float64 `validate:"len=1113.00"` LenMultiple []string `validate:"len=7"` MinString string `validate:"min=1"` MinNumber float64 `validate:"min=1113.00"` MinMultiple []string `validate:"min=7"` MaxString string `validate:"max=3"` MaxNumber float64 `validate:"max=1113.00"` MaxMultiple []string `validate:"max=7"` EqString string `validate:"eq=3"` EqNumber float64 `validate:"eq=2.33"` EqMultiple []string `validate:"eq=7"` NeString string `validate:"ne="` NeNumber float64 `validate:"ne=0.00"` NeMultiple []string `validate:"ne=0"` LtString string `validate:"lt=3"` LtNumber float64 `validate:"lt=5.56"` LtMultiple []string `validate:"lt=2"` LtTime time.Time `validate:"lt"` LteString string `validate:"lte=3"` LteNumber float64 `validate:"lte=5.56"` LteMultiple []string `validate:"lte=2"` LteTime time.Time `validate:"lte"` GtString string `validate:"gt=3"` GtNumber float64 `validate:"gt=5.56"` GtMultiple []string `validate:"gt=2"` GtTime time.Time `validate:"gt"` GteString string `validate:"gte=3"` GteNumber float64 `validate:"gte=5.56"` GteMultiple []string `validate:"gte=2"` GteTime time.Time `validate:"gte"` EqFieldString string `validate:"eqfield=MaxString"` EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"` NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"` GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"` GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"` LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"` LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"` NeFieldString string `validate:"nefield=EqFieldString"` GtFieldString string `validate:"gtfield=MaxString"` GteFieldString string `validate:"gtefield=MaxString"` LtFieldString string `validate:"ltfield=MaxString"` LteFieldString string `validate:"ltefield=MaxString"` AlphaString string `validate:"alpha"` AlphanumString string `validate:"alphanum"` NumericString string `validate:"numeric"` NumberString string `validate:"number"` HexadecimalString string `validate:"hexadecimal"` HexColorString string `validate:"hexcolor"` RGBColorString string `validate:"rgb"` RGBAColorString string `validate:"rgba"` HSLColorString string `validate:"hsl"` HSLAColorString string `validate:"hsla"` Email string `validate:"email"` URL string `validate:"url"` URI string `validate:"uri"` Base64 string `validate:"base64"` Contains string `validate:"contains=purpose"` ContainsAny string `validate:"containsany=!@#$"` Excludes string `validate:"excludes=text"` ExcludesAll string `validate:"excludesall=!@#$"` ExcludesRune string `validate:"excludesrune=☻"` ISBN string `validate:"isbn"` ISBN10 string `validate:"isbn10"` ISBN13 string `validate:"isbn13"` UUID string `validate:"uuid"` UUID3 string `validate:"uuid3"` UUID4 string `validate:"uuid4"` UUID5 string `validate:"uuid5"` ASCII string `validate:"ascii"` PrintableASCII string `validate:"printascii"` MultiByte string `validate:"multibyte"` DataURI string `validate:"datauri"` Latitude string `validate:"latitude"` Longitude string `validate:"longitude"` SSN string `validate:"ssn"` IP string `validate:"ip"` IPv4 string `validate:"ipv4"` IPv6 string `validate:"ipv6"` CIDR string `validate:"cidr"` CIDRv4 string `validate:"cidrv4"` CIDRv6 string `validate:"cidrv6"` TCPAddr string `validate:"tcp_addr"` TCPAddrv4 string `validate:"tcp4_addr"` TCPAddrv6 string `validate:"tcp6_addr"` UDPAddr string `validate:"udp_addr"` UDPAddrv4 string `validate:"udp4_addr"` UDPAddrv6 string `validate:"udp6_addr"` IPAddr string `validate:"ip_addr"` IPAddrv4 string `validate:"ip4_addr"` IPAddrv6 string `validate:"ip6_addr"` UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future MAC string `validate:"mac"` IsColor string `validate:"iscolor"` StrPtrMinLen *string `validate:"min=10"` StrPtrMaxLen *string `validate:"max=1"` StrPtrLen *string `validate:"len=2"` StrPtrLt *string `validate:"lt=1"` StrPtrLte *string `validate:"lte=1"` StrPtrGt *string `validate:"gt=10"` StrPtrGte *string `validate:"gte=10"` OneOfString string `validate:"oneof=red green"` OneOfInt int `validate:"oneof=5 63"` UniqueSlice []string `validate:"unique"` UniqueArray [3]string `validate:"unique"` UniqueMap map[string]string `validate:"unique"` JSONString string `validate:"json"` LowercaseString string `validate:"lowercase"` UppercaseString string `validate:"uppercase"` Datetime string `validate:"datetime=2006-01-02"` } var test Test test.Inner.EqCSFieldString = "1234" test.Inner.GtCSFieldString = "1234" test.Inner.GteCSFieldString = "1234" test.MaxString = "1234" test.MaxNumber = 2000 test.MaxMultiple = make([]string, 9) test.LtString = "1234" test.LtNumber = 6 test.LtMultiple = make([]string, 3) test.LtTime = time.Now().Add(time.Hour * 24) test.LteString = "1234" test.LteNumber = 6 test.LteMultiple = make([]string, 3) test.LteTime = time.Now().Add(time.Hour * 24) test.LtFieldString = "12345" test.LteFieldString = "12345" test.LtCSFieldString = "1234" test.LteCSFieldString = "1234" test.AlphaString = "abc3" test.AlphanumString = "abc3!" test.NumericString = "12E.00" test.NumberString = "12E" test.Excludes = "this is some test text" test.ExcludesAll = "This is Great!" test.ExcludesRune = "Love it ☻" test.ASCII = "カタカナ" test.PrintableASCII = "カタカナ" test.MultiByte = "1234feerf" test.LowercaseString = "ABCDEFG" test.UppercaseString = "abcdefg" s := "toolong" test.StrPtrMaxLen = &s test.StrPtrLen = &s test.UniqueSlice = []string{"1234", "1234"} test.UniqueMap = map[string]string{"key1": "1234", "key2": "1234"} test.Datetime = "2008-Feb-01" err = validate.Struct(test) NotEqual(t, err, nil) errs, ok := err.(validator.ValidationErrors) Equal(t, ok, true) tests := []struct { ns string expected string }{ { ns: "Test.IsColor", expected: "IsColor deve ser uma cor válida", }, { ns: "Test.MAC", expected: "MAC deve conter um endereço MAC válido", }, { ns: "Test.IPAddr", expected: "IPAddr deve ser um endereço IP resolvível", }, { ns: "Test.IPAddrv4", expected: "IPAddrv4 deve ser um endereço IPv4 resolvível", }, { ns: "Test.IPAddrv6", expected: "IPAddrv6 deve ser um endereço IPv6 resolvível", }, { ns: "Test.UDPAddr", expected: "UDPAddr deve ser um endereço UDP válido", }, { ns: "Test.UDPAddrv4", expected: "UDPAddrv4 deve ser um endereço UDP IPv4 válido", }, { ns: "Test.UDPAddrv6", expected: "UDPAddrv6 deve ser um endereço UDP IPv6 válido", }, { ns: "Test.TCPAddr", expected: "TCPAddr deve ser um endereço TCP válido", }, { ns: "Test.TCPAddrv4", expected: "TCPAddrv4 deve ser um endereço TCP IPv4 válido", }, { ns: "Test.TCPAddrv6", expected: "TCPAddrv6 deve ser um endereço TCP IPv6 válido", }, { ns: "Test.CIDR", expected: "CIDR não respeita a notação CIDR", }, { ns: "Test.CIDRv4", expected: "CIDRv4 não respeita a notação CIDR para um endereço IPv4", }, { ns: "Test.CIDRv6", expected: "CIDRv6 não respeita a notação CIDR para um endereço IPv6", }, { ns: "Test.SSN", expected: "SSN deve ser um número SSN válido", }, { ns: "Test.IP", expected: "IP deve ser um endereço IP válido", }, { ns: "Test.IPv4", expected: "IPv4 deve ser um endereço IPv4 válido", }, { ns: "Test.IPv6", expected: "IPv6 deve ser um endereço IPv6 válido", }, { ns: "Test.DataURI", expected: "DataURI deve conter um Data URI válido", }, { ns: "Test.Latitude", expected: "Latitude deve conter uma coordenada de latitude válida", }, { ns: "Test.Longitude", expected: "Longitude deve conter uma coordenada de longitude válida", }, { ns: "Test.MultiByte", expected: "MultiByte deve conter caracteres multibyte", }, { ns: "Test.ASCII", expected: "ASCII deve conter apenas caracteres ascii", }, { ns: "Test.PrintableASCII", expected: "PrintableASCII deve conter apenas caracteres ascii imprimíveis", }, { ns: "Test.UUID", expected: "UUID deve ser um UUID válido", }, { ns: "Test.UUID3", expected: "UUID3 deve ser um UUID versão 3 válido", }, { ns: "Test.UUID4", expected: "UUID4 deve ser um UUID versão 4 válido", }, { ns: "Test.UUID5", expected: "UUID5 deve ser um UUID versão 5 válido", }, { ns: "Test.ISBN", expected: "ISBN deve ser um número de ISBN válido", }, { ns: "Test.ISBN10", expected: "ISBN10 deve ser um número ISBN-10 válido", }, { ns: "Test.ISBN13", expected: "ISBN13 deve ser um número ISBN-13 válido", }, { ns: "Test.Excludes", expected: "Excludes não deve conter o texto 'text'", }, { ns: "Test.ExcludesAll", expected: "ExcludesAll não deve conter os seguintes caracteres '!@#$'", }, { ns: "Test.ExcludesRune", expected: "ExcludesRune não pode conter o seguinte '☻'", }, { ns: "Test.ContainsAny", expected: "ContainsAny deve conter pelo menos um dos seguintes caracteres '!@#$'", }, { ns: "Test.Contains", expected: "Contains deve conter o texto 'purpose'", }, { ns: "Test.Base64", expected: "Base64 deve ser uma string Base64 válida", }, { ns: "Test.Email", expected: "Email deve ser um endereço de e-mail válido", }, { ns: "Test.URL", expected: "URL deve ser um URL válido", }, { ns: "Test.URI", expected: "URI deve ser um URI válido", }, { ns: "Test.RGBColorString", expected: "RGBColorString deve ser uma cor RGB válida", }, { ns: "Test.RGBAColorString", expected: "RGBAColorString deve ser uma cor RGBA válida", }, { ns: "Test.HSLColorString", expected: "HSLColorString deve ser uma cor HSL válida", }, { ns: "Test.HSLAColorString", expected: "HSLAColorString deve ser uma cor HSLA válida", }, { ns: "Test.HexadecimalString", expected: "HexadecimalString deve ser um hexadecimal válido", }, { ns: "Test.HexColorString", expected: "HexColorString deve ser uma cor HEX válida", }, { ns: "Test.NumberString", expected: "NumberString deve ser um número válido", }, { ns: "Test.NumericString", expected: "NumericString deve ser um valor numérico válido", }, { ns: "Test.AlphanumString", expected: "AlphanumString deve conter apenas caracteres alfanuméricos", }, { ns: "Test.AlphaString", expected: "AlphaString deve conter apenas caracteres alfabéticos", }, { ns: "Test.LtFieldString", expected: "LtFieldString deve ser menor que MaxString", }, { ns: "Test.LteFieldString", expected: "LteFieldString deve ser menor ou igual que MaxString", }, { ns: "Test.GtFieldString", expected: "GtFieldString deve ser maior que MaxString", }, { ns: "Test.GteFieldString", expected: "GteFieldString deve ser maior ou igual que MaxString", }, { ns: "Test.NeFieldString", expected: "NeFieldString não deve ser igual a EqFieldString", }, { ns: "Test.LtCSFieldString", expected: "LtCSFieldString deve ser menor que Inner.LtCSFieldString", }, { ns: "Test.LteCSFieldString", expected: "LteCSFieldString deve ser menor ou igual que Inner.LteCSFieldString", }, { ns: "Test.GtCSFieldString", expected: "GtCSFieldString deve ser maior que Inner.GtCSFieldString", }, { ns: "Test.GteCSFieldString", expected: "GteCSFieldString deve ser maior ou igual que Inner.GteCSFieldString", }, { ns: "Test.NeCSFieldString", expected: "NeCSFieldString não deve ser igual a Inner.NeCSFieldString", }, { ns: "Test.EqCSFieldString", expected: "EqCSFieldString deve ser igual a Inner.EqCSFieldString", }, { ns: "Test.EqFieldString", expected: "EqFieldString deve ser igual a MaxString", }, { ns: "Test.GteString", expected: "GteString deve ter pelo menos 3 caracteres", }, { ns: "Test.GteNumber", expected: "GteNumber deve ser maior ou igual a 5,56", }, { ns: "Test.GteMultiple", expected: "GteMultiple deve conter pelo menos 2 items", }, { ns: "Test.GteTime", expected: "GteTime deve ser posterior ou igual à data/hora atual", }, { ns: "Test.GtString", expected: "GtString deve conter mais de 3 caracteres", }, { ns: "Test.GtNumber", expected: "GtNumber deve ser maior que 5,56", }, { ns: "Test.GtMultiple", expected: "GtMultiple deve conter mais de 2 items", }, { ns: "Test.GtTime", expected: "GtTime deve ser posterior à data/hora atual", }, { ns: "Test.LteString", expected: "LteString deve ter no máximo 3 caracteres", }, { ns: "Test.LteNumber", expected: "LteNumber deve ser menor ou igual a 5,56", }, { ns: "Test.LteMultiple", expected: "LteMultiple deve conter no máximo 2 items", }, { ns: "Test.LteTime", expected: "LteTime deve ser anterior ou igual à data/hora atual", }, { ns: "Test.LtString", expected: "LtString deve ter menos de 3 caracteres", }, { ns: "Test.LtNumber", expected: "LtNumber deve ser menor que 5,56", }, { ns: "Test.LtMultiple", expected: "LtMultiple deve conter menos de 2 items", }, { ns: "Test.LtTime", expected: "LtTime deve ser anterior à data / hora atual", }, { ns: "Test.NeString", expected: "NeString não deve ser igual a ", }, { ns: "Test.NeNumber", expected: "NeNumber não deve ser igual a 0.00", }, { ns: "Test.NeMultiple", expected: "NeMultiple não deve ser igual a 0", }, { ns: "Test.EqString", expected: "EqString não é igual a 3", }, { ns: "Test.EqNumber", expected: "EqNumber não é igual a 2.33", }, { ns: "Test.EqMultiple", expected: "EqMultiple não é igual a 7", }, { ns: "Test.MaxString", expected: "MaxString deve ter no máximo 3 caracteres", }, { ns: "Test.MaxNumber", expected: "MaxNumber deve ser 1.113,00 ou menos", }, { ns: "Test.MaxMultiple", expected: "MaxMultiple deve conter no máximo 7 items", }, { ns: "Test.MinString", expected: "MinString deve ter pelo menos 1 caractere", }, { ns: "Test.MinNumber", expected: "MinNumber deve ser 1.113,00 ou superior", }, { ns: "Test.MinMultiple", expected: "MinMultiple deve conter pelo menos 7 items", }, { ns: "Test.LenString", expected: "LenString deve ter 1 caractere", }, { ns: "Test.LenNumber", expected: "LenNumber deve ser igual a 1.113,00", }, { ns: "Test.LenMultiple", expected: "LenMultiple deve conter 7 items", }, { ns: "Test.RequiredString", expected: "RequiredString é obrigatório", }, { ns: "Test.RequiredNumber", expected: "RequiredNumber é obrigatório", }, { ns: "Test.RequiredMultiple", expected: "RequiredMultiple é obrigatório", }, { ns: "Test.StrPtrMinLen", expected: "StrPtrMinLen deve ter pelo menos 10 caracteres", }, { ns: "Test.StrPtrMaxLen", expected: "StrPtrMaxLen deve ter no máximo 1 caractere", }, { ns: "Test.StrPtrLen", expected: "StrPtrLen deve ter 2 caracteres", }, { ns: "Test.StrPtrLt", expected: "StrPtrLt deve ter menos de 1 caractere", }, { ns: "Test.StrPtrLte", expected: "StrPtrLte deve ter no máximo 1 caractere", }, { ns: "Test.StrPtrGt", expected: "StrPtrGt deve conter mais de 10 caracteres", }, { ns: "Test.StrPtrGte", expected: "StrPtrGte deve ter pelo menos 10 caracteres", }, { ns: "Test.OneOfString", expected: "OneOfString deve ser um de [red green]", }, { ns: "Test.OneOfInt", expected: "OneOfInt deve ser um de [5 63]", }, { ns: "Test.UniqueSlice", expected: "UniqueSlice deve conter valores únicos", }, { ns: "Test.UniqueArray", expected: "UniqueArray deve conter valores únicos", }, { ns: "Test.UniqueMap", expected: "UniqueMap deve conter valores únicos", }, { ns: "Test.JSONString", expected: "JSONString deve ser uma string json válida", }, { ns: "Test.LowercaseString", expected: "LowercaseString deve estar em minuscúlas", }, { ns: "Test.UppercaseString", expected: "UppercaseString deve estar em maiúsculas", }, { ns: "Test.Datetime", expected: "Datetime não está no formato 2006-01-02", }, } for _, tt := range tests { var fe validator.FieldError for _, e := range errs { if tt.ns == e.Namespace() { fe = e break } } NotEqual(t, fe, nil) Equal(t, tt.expected, fe.Translate(trans)) } } validator-10.4.1/translations/pt_BR/000077500000000000000000000000001374261122600173155ustar00rootroot00000000000000validator-10.4.1/translations/pt_BR/pt_BR.go000066400000000000000000000763701374261122600206670ustar00rootroot00000000000000package pt_BR import ( "fmt" "log" "reflect" "strconv" "strings" "time" "github.com/go-playground/locales" ut "github.com/go-playground/universal-translator" "github.com/go-playground/validator/v10" ) // RegisterDefaultTranslations registers a set of default translations // for all built in tag's in validator; you may add your own as desired. func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (err error) { translations := []struct { tag string translation string override bool customRegisFunc validator.RegisterTranslationsFunc customTransFunc validator.TranslationFunc }{ { tag: "required", translation: "{0} é um campo requerido", override: false, }, { tag: "len", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("len-string", "{0} deve ter {1}", false); err != nil { return } if err = ut.AddCardinal("len-string-character", "{0} caractere", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("len-string-character", "{0} caracteres", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("len-number", "{0} deve ser igual a {1}", false); err != nil { return } if err = ut.Add("len-items", "{0} deve conter {1}", false); err != nil { return } if err = ut.AddCardinal("len-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("len-items-item", "{0} itens", locales.PluralRuleOther, false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var digits uint64 var kind reflect.Kind if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { goto END } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string c, err = ut.C("len-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("len-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string c, err = ut.C("len-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("len-items", fe.Field(), c) default: t, err = ut.T("len-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("alerta: erro na tradução FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "min", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("min-string", "{0} deve ter pelo menos {1}", false); err != nil { return } if err = ut.AddCardinal("min-string-character", "{0} caractere", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("min-string-character", "{0} caracteres", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("min-number", "{0} deve ser {1} ou superior", false); err != nil { return } if err = ut.Add("min-items", "{0} deve conter pelo menos {1}", false); err != nil { return } if err = ut.AddCardinal("min-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("min-items-item", "{0} itens", locales.PluralRuleOther, false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var digits uint64 var kind reflect.Kind if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { goto END } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string c, err = ut.C("min-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("min-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string c, err = ut.C("min-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("min-items", fe.Field(), c) default: t, err = ut.T("min-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("alerta: erro na tradução FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "max", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("max-string", "{0} deve ter no máximo {1}", false); err != nil { return } if err = ut.AddCardinal("max-string-character", "{0} caractere", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("max-string-character", "{0} caracteres", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("max-number", "{0} deve ser {1} ou menor", false); err != nil { return } if err = ut.Add("max-items", "{0} deve conter no máximo {1}", false); err != nil { return } if err = ut.AddCardinal("max-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("max-items-item", "{0} itens", locales.PluralRuleOther, false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var digits uint64 var kind reflect.Kind if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { goto END } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string c, err = ut.C("max-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("max-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string c, err = ut.C("max-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("max-items", fe.Field(), c) default: t, err = ut.T("max-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("alerta: erro na tradução FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "eq", translation: "{0} não é igual a {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { fmt.Printf("alerta: erro na tradução FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ne", translation: "{0} não deve ser igual a {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { fmt.Printf("alerta: erro na tradução FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "lt", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("lt-string", "{0} deve ter menos de {1}", false); err != nil { return } if err = ut.AddCardinal("lt-string-character", "{0} caractere", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("lt-string-character", "{0} caracteres", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lt-number", "{0} deve ser menor que {1}", false); err != nil { return } if err = ut.Add("lt-items", "{0} deve conter menos de {1}", false); err != nil { return } if err = ut.AddCardinal("lt-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("lt-items-item", "{0} itens", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lt-datetime", "{0} deve ser inferior à Data e Hora atual", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("lt-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lt-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("lt-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lt-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("a tag '%s' não pode ser usada em uma struct type", fe.Tag()) goto END } t, err = ut.T("lt-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("lt-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("alerta: erro na tradução FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "lte", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("lte-string", "{0} deve ter no máximo {1}", false); err != nil { return } if err = ut.AddCardinal("lte-string-character", "{0} caractere", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("lte-string-character", "{0} caracteres", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lte-number", "{0} deve ser {1} ou menor", false); err != nil { return } if err = ut.Add("lte-items", "{0} deve conter no máximo {1}", false); err != nil { return } if err = ut.AddCardinal("lte-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("lte-items-item", "{0} itens", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lte-datetime", "{0} deve ser menor ou igual à Data e Hora atual", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("lte-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lte-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("lte-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lte-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("a tag '%s' não pode ser usado em uma struct type", fe.Tag()) goto END } t, err = ut.T("lte-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("lte-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("alerta: erro na tradução FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "gt", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("gt-string", "{0} deve ter mais de {1}", false); err != nil { return } if err = ut.AddCardinal("gt-string-character", "{0} caractere", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("gt-string-character", "{0} caracteres", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gt-number", "{0} deve ser maior do que {1}", false); err != nil { return } if err = ut.Add("gt-items", "{0} deve conter mais de {1}", false); err != nil { return } if err = ut.AddCardinal("gt-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("gt-items-item", "{0} itens", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gt-datetime", "{0} deve ser maior que a Data e Hora atual", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("gt-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gt-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("gt-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gt-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("a tag '%s' não pode ser usado em uma struct type", fe.Tag()) goto END } t, err = ut.T("gt-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("gt-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("alerta: erro na tradução FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "gte", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("gte-string", "{0} deve ter pelo menos {1}", false); err != nil { return } if err = ut.AddCardinal("gte-string-character", "{0} caractere", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("gte-string-character", "{0} caracteres", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gte-number", "{0} deve ser {1} ou superior", false); err != nil { return } if err = ut.Add("gte-items", "{0} deve conter pelo menos {1}", false); err != nil { return } if err = ut.AddCardinal("gte-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("gte-items-item", "{0} itens", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gte-datetime", "{0} deve ser maior ou igual à Data e Hora atual", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("gte-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gte-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("gte-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gte-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("a tag '%s' não pode ser usado em uma struct type", fe.Tag()) goto END } t, err = ut.T("gte-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("gte-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("alerta: erro na tradução FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "eqfield", translation: "{0} deve ser igual a {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("alerta: erro na tradução FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "eqcsfield", translation: "{0} deve ser igual a {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("alerta: erro na tradução FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "necsfield", translation: "{0} não deve ser igual a {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("alerta: erro na tradução FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtcsfield", translation: "{0} deve ser maior do que {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("alerta: erro na tradução FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtecsfield", translation: "{0} deve ser maior ou igual a {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("alerta: erro na tradução FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltcsfield", translation: "{0} deve ser menor que {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("alerta: erro na tradução FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltecsfield", translation: "{0} deve ser menor ou igual a {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("alerta: erro na tradução FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "nefield", translation: "{0} não deve ser igual a {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("alerta: erro na tradução FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtfield", translation: "{0} deve ser maior do que {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("alerta: erro na tradução FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtefield", translation: "{0} deve ser maior ou igual a {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("alerta: erro na tradução FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltfield", translation: "{0} deve ser menor que {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("alerta: erro na tradução FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltefield", translation: "{0} deve ser menor ou igual a {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("alerta: erro na tradução FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "alpha", translation: "{0} deve conter caracteres alfabéticos", override: false, }, { tag: "alphanum", translation: "{0} deve conter caracteres alfanuméricos", override: false, }, { tag: "numeric", translation: "{0} deve ser um valor numérico válido", override: false, }, { tag: "number", translation: "{0} deve ser um número válido", override: false, }, { tag: "hexadecimal", translation: "{0} deve ser um hexadecimal válido", override: false, }, { tag: "hexcolor", translation: "{0} deve ser uma cor HEX válida", override: false, }, { tag: "rgb", translation: "{0} deve ser uma cor RGB válida", override: false, }, { tag: "rgba", translation: "{0} deve ser uma cor RGBA válida", override: false, }, { tag: "hsl", translation: "{0} deve ser uma cor HSL válida", override: false, }, { tag: "hsla", translation: "{0} deve ser uma cor HSLA válida", override: false, }, { tag: "email", translation: "{0} deve ser um endereço de e-mail válido", override: false, }, { tag: "url", translation: "{0} deve ser uma URL válida", override: false, }, { tag: "uri", translation: "{0} deve ser uma URI válida", override: false, }, { tag: "base64", translation: "{0} deve ser uma string Base64 válida", override: false, }, { tag: "contains", translation: "{0} deve conter o texto '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("alerta: erro na tradução FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "containsany", translation: "{0} deve conter pelo menos um dos caracteres '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("alerta: erro na tradução FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "excludes", translation: "{0} não deve conter o texto '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("alerta: erro na tradução FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "excludesall", translation: "{0} não deve conter nenhum dos caracteres '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("alerta: erro na tradução FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "excludesrune", translation: "{0} não deve conter '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("alerta: erro na tradução FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "isbn", translation: "{0} deve ser um número ISBN válido", override: false, }, { tag: "isbn10", translation: "{0} deve ser um número ISBN-10 válido", override: false, }, { tag: "isbn13", translation: "{0} deve ser um número ISBN-13 válido", override: false, }, { tag: "uuid", translation: "{0} deve ser um UUID válido", override: false, }, { tag: "uuid3", translation: "{0} deve ser um UUID versão 3 válido", override: false, }, { tag: "uuid4", translation: "{0} deve ser um UUID versão 4 válido", override: false, }, { tag: "uuid5", translation: "{0} deve ser um UUID versão 5 válido", override: false, }, { tag: "ascii", translation: "{0} deve conter apenas caracteres ascii", override: false, }, { tag: "printascii", translation: "{0} deve conter apenas caracteres ascii imprimíveis", override: false, }, { tag: "multibyte", translation: "{0} deve conter caracteres multibyte", override: false, }, { tag: "datauri", translation: "{0} deve conter um URI data válido", override: false, }, { tag: "latitude", translation: "{0} deve conter uma coordenada de latitude válida", override: false, }, { tag: "longitude", translation: "{0} deve conter uma coordenada de longitude válida", override: false, }, { tag: "ssn", translation: "{0} deve ser um número SSN válido", override: false, }, { tag: "ipv4", translation: "{0} deve ser um endereço IPv4 válido", override: false, }, { tag: "ipv6", translation: "{0} deve ser um endereço IPv6 válido", override: false, }, { tag: "ip", translation: "{0} deve ser um endereço de IP válido", override: false, }, { tag: "cidr", translation: "{0} deve conter uma notação CIDR válida", override: false, }, { tag: "cidrv4", translation: "{0} deve conter uma notação CIDR válida para um endereço IPv4", override: false, }, { tag: "cidrv6", translation: "{0} deve conter uma notação CIDR válida para um endereço IPv6", override: false, }, { tag: "tcp_addr", translation: "{0} deve ser um endereço TCP válido", override: false, }, { tag: "tcp4_addr", translation: "{0} deve ser um endereço IPv4 TCP válido", override: false, }, { tag: "tcp6_addr", translation: "{0} deve ser um endereço IPv6 TCP válido", override: false, }, { tag: "udp_addr", translation: "{0} deve ser um endereço UDP válido", override: false, }, { tag: "udp4_addr", translation: "{0} deve ser um endereço IPv4 UDP válido", override: false, }, { tag: "udp6_addr", translation: "{0} deve ser um endereço IPv6 UDP válido", override: false, }, { tag: "ip_addr", translation: "{0} deve ser um endereço IP resolvível", override: false, }, { tag: "ip4_addr", translation: "{0} deve ser um endereço IPv4 resolvível", override: false, }, { tag: "ip6_addr", translation: "{0} deve ser um endereço IPv6 resolvível", override: false, }, { tag: "unix_addr", translation: "{0} deve ser um endereço UNIX resolvível", override: false, }, { tag: "mac", translation: "{0} deve conter um endereço MAC válido", override: false, }, { tag: "iscolor", translation: "{0} deve ser uma cor válida", override: false, }, { tag: "oneof", translation: "{0} deve ser um de [{1}]", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { s, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("alerta: erro na tradução FieldError: %#v", fe) return fe.(error).Error() } return s }, }, } for _, t := range translations { if t.customTransFunc != nil && t.customRegisFunc != nil { err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, t.customTransFunc) } else if t.customTransFunc != nil && t.customRegisFunc == nil { err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), t.customTransFunc) } else if t.customTransFunc == nil && t.customRegisFunc != nil { err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, translateFunc) } else { err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), translateFunc) } if err != nil { return } } return } func registrationFunc(tag string, translation string, override bool) validator.RegisterTranslationsFunc { return func(ut ut.Translator) (err error) { if err = ut.Add(tag, translation, override); err != nil { return } return } } func translateFunc(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field()) if err != nil { log.Printf("alerta: erro na tradução FieldError: %#v", fe) return fe.(error).Error() } return t } validator-10.4.1/translations/pt_BR/pt_BR_test.go000066400000000000000000000435411374261122600217200ustar00rootroot00000000000000package pt_BR import ( "testing" "time" brazilian_portuguese "github.com/go-playground/locales/pt_BR" ut "github.com/go-playground/universal-translator" "github.com/go-playground/validator/v10" . "github.com/go-playground/assert/v2" ) func TestTranslations(t *testing.T) { ptbr := brazilian_portuguese.New() uni := ut.New(ptbr, ptbr) trans, _ := uni.GetTranslator("pt_BR") validate := validator.New() err := RegisterDefaultTranslations(validate, trans) Equal(t, err, nil) type Inner struct { EqCSFieldString string NeCSFieldString string GtCSFieldString string GteCSFieldString string LtCSFieldString string LteCSFieldString string } type Test struct { Inner Inner RequiredString string `validate:"required"` RequiredNumber int `validate:"required"` RequiredMultiple []string `validate:"required"` LenString string `validate:"len=1"` LenNumber float64 `validate:"len=1113.00"` LenMultiple []string `validate:"len=7"` MinString string `validate:"min=1"` MinNumber float64 `validate:"min=1113.00"` MinMultiple []string `validate:"min=7"` MaxString string `validate:"max=3"` MaxNumber float64 `validate:"max=1113.00"` MaxMultiple []string `validate:"max=7"` EqString string `validate:"eq=3"` EqNumber float64 `validate:"eq=2.33"` EqMultiple []string `validate:"eq=7"` NeString string `validate:"ne="` NeNumber float64 `validate:"ne=0.00"` NeMultiple []string `validate:"ne=0"` LtString string `validate:"lt=3"` LtNumber float64 `validate:"lt=5.56"` LtMultiple []string `validate:"lt=2"` LtTime time.Time `validate:"lt"` LteString string `validate:"lte=3"` LteNumber float64 `validate:"lte=5.56"` LteMultiple []string `validate:"lte=2"` LteTime time.Time `validate:"lte"` GtString string `validate:"gt=3"` GtNumber float64 `validate:"gt=5.56"` GtMultiple []string `validate:"gt=2"` GtTime time.Time `validate:"gt"` GteString string `validate:"gte=3"` GteNumber float64 `validate:"gte=5.56"` GteMultiple []string `validate:"gte=2"` GteTime time.Time `validate:"gte"` EqFieldString string `validate:"eqfield=MaxString"` EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"` NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"` GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"` GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"` LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"` LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"` NeFieldString string `validate:"nefield=EqFieldString"` GtFieldString string `validate:"gtfield=MaxString"` GteFieldString string `validate:"gtefield=MaxString"` LtFieldString string `validate:"ltfield=MaxString"` LteFieldString string `validate:"ltefield=MaxString"` AlphaString string `validate:"alpha"` AlphanumString string `validate:"alphanum"` NumericString string `validate:"numeric"` NumberString string `validate:"number"` HexadecimalString string `validate:"hexadecimal"` HexColorString string `validate:"hexcolor"` RGBColorString string `validate:"rgb"` RGBAColorString string `validate:"rgba"` HSLColorString string `validate:"hsl"` HSLAColorString string `validate:"hsla"` Email string `validate:"email"` URL string `validate:"url"` URI string `validate:"uri"` Base64 string `validate:"base64"` Contains string `validate:"contains=purpose"` ContainsAny string `validate:"containsany=!@#$"` Excludes string `validate:"excludes=text"` ExcludesAll string `validate:"excludesall=!@#$"` ExcludesRune string `validate:"excludesrune=☻"` ISBN string `validate:"isbn"` ISBN10 string `validate:"isbn10"` ISBN13 string `validate:"isbn13"` UUID string `validate:"uuid"` UUID3 string `validate:"uuid3"` UUID4 string `validate:"uuid4"` UUID5 string `validate:"uuid5"` ASCII string `validate:"ascii"` PrintableASCII string `validate:"printascii"` MultiByte string `validate:"multibyte"` DataURI string `validate:"datauri"` Latitude string `validate:"latitude"` Longitude string `validate:"longitude"` SSN string `validate:"ssn"` IP string `validate:"ip"` IPv4 string `validate:"ipv4"` IPv6 string `validate:"ipv6"` CIDR string `validate:"cidr"` CIDRv4 string `validate:"cidrv4"` CIDRv6 string `validate:"cidrv6"` TCPAddr string `validate:"tcp_addr"` TCPAddrv4 string `validate:"tcp4_addr"` TCPAddrv6 string `validate:"tcp6_addr"` UDPAddr string `validate:"udp_addr"` UDPAddrv4 string `validate:"udp4_addr"` UDPAddrv6 string `validate:"udp6_addr"` IPAddr string `validate:"ip_addr"` IPAddrv4 string `validate:"ip4_addr"` IPAddrv6 string `validate:"ip6_addr"` UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future MAC string `validate:"mac"` IsColor string `validate:"iscolor"` StrPtrMinLen *string `validate:"min=10"` StrPtrMaxLen *string `validate:"max=1"` StrPtrLen *string `validate:"len=2"` StrPtrLt *string `validate:"lt=1"` StrPtrLte *string `validate:"lte=1"` StrPtrGt *string `validate:"gt=10"` StrPtrGte *string `validate:"gte=10"` OneOfString string `validate:"oneof=red green"` OneOfInt int `validate:"oneof=5 63"` } var test Test test.Inner.EqCSFieldString = "1234" test.Inner.GtCSFieldString = "1234" test.Inner.GteCSFieldString = "1234" test.MaxString = "1234" test.MaxNumber = 2000 test.MaxMultiple = make([]string, 9) test.LtString = "1234" test.LtNumber = 6 test.LtMultiple = make([]string, 3) test.LtTime = time.Now().Add(time.Hour * 24) test.LteString = "1234" test.LteNumber = 6 test.LteMultiple = make([]string, 3) test.LteTime = time.Now().Add(time.Hour * 24) test.LtFieldString = "12345" test.LteFieldString = "12345" test.LtCSFieldString = "1234" test.LteCSFieldString = "1234" test.AlphaString = "abc3" test.AlphanumString = "abc3!" test.NumericString = "12E.00" test.NumberString = "12E" test.Excludes = "este é um texto de teste" test.ExcludesAll = "Isso é Ótimo!" test.ExcludesRune = "Amo isso ☻" test.ASCII = "カタカナ" test.PrintableASCII = "カタカナ" test.MultiByte = "1234feerf" s := "toolong" test.StrPtrMaxLen = &s test.StrPtrLen = &s err = validate.Struct(test) NotEqual(t, err, nil) errs, ok := err.(validator.ValidationErrors) Equal(t, ok, true) tests := []struct { ns string expected string }{ { ns: "Test.IsColor", expected: "IsColor deve ser uma cor válida", }, { ns: "Test.MAC", expected: "MAC deve conter um endereço MAC válido", }, { ns: "Test.IPAddr", expected: "IPAddr deve ser um endereço IP resolvível", }, { ns: "Test.IPAddrv4", expected: "IPAddrv4 deve ser um endereço IPv4 resolvível", }, { ns: "Test.IPAddrv6", expected: "IPAddrv6 deve ser um endereço IPv6 resolvível", }, { ns: "Test.UDPAddr", expected: "UDPAddr deve ser um endereço UDP válido", }, { ns: "Test.UDPAddrv4", expected: "UDPAddrv4 deve ser um endereço IPv4 UDP válido", }, { ns: "Test.UDPAddrv6", expected: "UDPAddrv6 deve ser um endereço IPv6 UDP válido", }, { ns: "Test.TCPAddr", expected: "TCPAddr deve ser um endereço TCP válido", }, { ns: "Test.TCPAddrv4", expected: "TCPAddrv4 deve ser um endereço IPv4 TCP válido", }, { ns: "Test.TCPAddrv6", expected: "TCPAddrv6 deve ser um endereço IPv6 TCP válido", }, { ns: "Test.CIDR", expected: "CIDR deve conter uma notação CIDR válida", }, { ns: "Test.CIDRv4", expected: "CIDRv4 deve conter uma notação CIDR válida para um endereço IPv4", }, { ns: "Test.CIDRv6", expected: "CIDRv6 deve conter uma notação CIDR válida para um endereço IPv6", }, { ns: "Test.SSN", expected: "SSN deve ser um número SSN válido", }, { ns: "Test.IP", expected: "IP deve ser um endereço de IP válido", }, { ns: "Test.IPv4", expected: "IPv4 deve ser um endereço IPv4 válido", }, { ns: "Test.IPv6", expected: "IPv6 deve ser um endereço IPv6 válido", }, { ns: "Test.DataURI", expected: "DataURI deve conter um URI data válido", }, { ns: "Test.Latitude", expected: "Latitude deve conter uma coordenada de latitude válida", }, { ns: "Test.Longitude", expected: "Longitude deve conter uma coordenada de longitude válida", }, { ns: "Test.MultiByte", expected: "MultiByte deve conter caracteres multibyte", }, { ns: "Test.ASCII", expected: "ASCII deve conter apenas caracteres ascii", }, { ns: "Test.PrintableASCII", expected: "PrintableASCII deve conter apenas caracteres ascii imprimíveis", }, { ns: "Test.UUID", expected: "UUID deve ser um UUID válido", }, { ns: "Test.UUID3", expected: "UUID3 deve ser um UUID versão 3 válido", }, { ns: "Test.UUID4", expected: "UUID4 deve ser um UUID versão 4 válido", }, { ns: "Test.UUID5", expected: "UUID5 deve ser um UUID versão 5 válido", }, { ns: "Test.ISBN", expected: "ISBN deve ser um número ISBN válido", }, { ns: "Test.ISBN10", expected: "ISBN10 deve ser um número ISBN-10 válido", }, { ns: "Test.ISBN13", expected: "ISBN13 deve ser um número ISBN-13 válido", }, { ns: "Test.Excludes", expected: "Excludes não deve conter o texto 'text'", }, { ns: "Test.ExcludesAll", expected: "ExcludesAll não deve conter nenhum dos caracteres '!@#$'", }, { ns: "Test.ExcludesRune", expected: "ExcludesRune não deve conter '☻'", }, { ns: "Test.ContainsAny", expected: "ContainsAny deve conter pelo menos um dos caracteres '!@#$'", }, { ns: "Test.Contains", expected: "Contains deve conter o texto 'purpose'", }, { ns: "Test.Base64", expected: "Base64 deve ser uma string Base64 válida", }, { ns: "Test.Email", expected: "Email deve ser um endereço de e-mail válido", }, { ns: "Test.URL", expected: "URL deve ser uma URL válida", }, { ns: "Test.URI", expected: "URI deve ser uma URI válida", }, { ns: "Test.RGBColorString", expected: "RGBColorString deve ser uma cor RGB válida", }, { ns: "Test.RGBAColorString", expected: "RGBAColorString deve ser uma cor RGBA válida", }, { ns: "Test.HSLColorString", expected: "HSLColorString deve ser uma cor HSL válida", }, { ns: "Test.HSLAColorString", expected: "HSLAColorString deve ser uma cor HSLA válida", }, { ns: "Test.HexadecimalString", expected: "HexadecimalString deve ser um hexadecimal válido", }, { ns: "Test.HexColorString", expected: "HexColorString deve ser uma cor HEX válida", }, { ns: "Test.NumberString", expected: "NumberString deve ser um número válido", }, { ns: "Test.NumericString", expected: "NumericString deve ser um valor numérico válido", }, { ns: "Test.AlphanumString", expected: "AlphanumString deve conter caracteres alfanuméricos", }, { ns: "Test.AlphaString", expected: "AlphaString deve conter caracteres alfabéticos", }, { ns: "Test.LtFieldString", expected: "LtFieldString deve ser menor que MaxString", }, { ns: "Test.LteFieldString", expected: "LteFieldString deve ser menor ou igual a MaxString", }, { ns: "Test.GtFieldString", expected: "GtFieldString deve ser maior do que MaxString", }, { ns: "Test.GteFieldString", expected: "GteFieldString deve ser maior ou igual a MaxString", }, { ns: "Test.NeFieldString", expected: "NeFieldString não deve ser igual a EqFieldString", }, { ns: "Test.LtCSFieldString", expected: "LtCSFieldString deve ser menor que Inner.LtCSFieldString", }, { ns: "Test.LteCSFieldString", expected: "LteCSFieldString deve ser menor ou igual a Inner.LteCSFieldString", }, { ns: "Test.GtCSFieldString", expected: "GtCSFieldString deve ser maior do que Inner.GtCSFieldString", }, { ns: "Test.GteCSFieldString", expected: "GteCSFieldString deve ser maior ou igual a Inner.GteCSFieldString", }, { ns: "Test.NeCSFieldString", expected: "NeCSFieldString não deve ser igual a Inner.NeCSFieldString", }, { ns: "Test.EqCSFieldString", expected: "EqCSFieldString deve ser igual a Inner.EqCSFieldString", }, { ns: "Test.EqFieldString", expected: "EqFieldString deve ser igual a MaxString", }, { ns: "Test.GteString", expected: "GteString deve ter pelo menos 3 caracteres", }, { ns: "Test.GteNumber", expected: "GteNumber deve ser 5,56 ou superior", }, { ns: "Test.GteMultiple", expected: "GteMultiple deve conter pelo menos 2 itens", }, { ns: "Test.GteTime", expected: "GteTime deve ser maior ou igual à Data e Hora atual", }, { ns: "Test.GtString", expected: "GtString deve ter mais de 3 caracteres", }, { ns: "Test.GtNumber", expected: "GtNumber deve ser maior do que 5,56", }, { ns: "Test.GtMultiple", expected: "GtMultiple deve conter mais de 2 itens", }, { ns: "Test.GtTime", expected: "GtTime deve ser maior que a Data e Hora atual", }, { ns: "Test.LteString", expected: "LteString deve ter no máximo 3 caracteres", }, { ns: "Test.LteNumber", expected: "LteNumber deve ser 5,56 ou menor", }, { ns: "Test.LteMultiple", expected: "LteMultiple deve conter no máximo 2 itens", }, { ns: "Test.LteTime", expected: "LteTime deve ser menor ou igual à Data e Hora atual", }, { ns: "Test.LtString", expected: "LtString deve ter menos de 3 caracteres", }, { ns: "Test.LtNumber", expected: "LtNumber deve ser menor que 5,56", }, { ns: "Test.LtMultiple", expected: "LtMultiple deve conter menos de 2 itens", }, { ns: "Test.LtTime", expected: "LtTime deve ser inferior à Data e Hora atual", }, { ns: "Test.NeString", expected: "NeString não deve ser igual a ", }, { ns: "Test.NeNumber", expected: "NeNumber não deve ser igual a 0.00", }, { ns: "Test.NeMultiple", expected: "NeMultiple não deve ser igual a 0", }, { ns: "Test.EqString", expected: "EqString não é igual a 3", }, { ns: "Test.EqNumber", expected: "EqNumber não é igual a 2.33", }, { ns: "Test.EqMultiple", expected: "EqMultiple não é igual a 7", }, { ns: "Test.MaxString", expected: "MaxString deve ter no máximo 3 caracteres", }, { ns: "Test.MaxNumber", expected: "MaxNumber deve ser 1.113,00 ou menor", }, { ns: "Test.MaxMultiple", expected: "MaxMultiple deve conter no máximo 7 itens", }, { ns: "Test.MinString", expected: "MinString deve ter pelo menos 1 caractere", }, { ns: "Test.MinNumber", expected: "MinNumber deve ser 1.113,00 ou superior", }, { ns: "Test.MinMultiple", expected: "MinMultiple deve conter pelo menos 7 itens", }, { ns: "Test.LenString", expected: "LenString deve ter 1 caractere", }, { ns: "Test.LenNumber", expected: "LenNumber deve ser igual a 1.113,00", }, { ns: "Test.LenMultiple", expected: "LenMultiple deve conter 7 itens", }, { ns: "Test.RequiredString", expected: "RequiredString é um campo requerido", }, { ns: "Test.RequiredNumber", expected: "RequiredNumber é um campo requerido", }, { ns: "Test.RequiredMultiple", expected: "RequiredMultiple é um campo requerido", }, { ns: "Test.StrPtrMinLen", expected: "StrPtrMinLen deve ter pelo menos 10 caracteres", }, { ns: "Test.StrPtrMaxLen", expected: "StrPtrMaxLen deve ter no máximo 1 caractere", }, { ns: "Test.StrPtrLen", expected: "StrPtrLen deve ter 2 caracteres", }, { ns: "Test.StrPtrLt", expected: "StrPtrLt deve ter menos de 1 caractere", }, { ns: "Test.StrPtrLte", expected: "StrPtrLte deve ter no máximo 1 caractere", }, { ns: "Test.StrPtrGt", expected: "StrPtrGt deve ter mais de 10 caracteres", }, { ns: "Test.StrPtrGte", expected: "StrPtrGte deve ter pelo menos 10 caracteres", }, { ns: "Test.OneOfString", expected: "OneOfString deve ser um de [red green]", }, { ns: "Test.OneOfInt", expected: "OneOfInt deve ser um de [5 63]", }, } for _, tt := range tests { var fe validator.FieldError for _, e := range errs { if tt.ns == e.Namespace() { fe = e break } } NotEqual(t, fe, nil) Equal(t, tt.expected, fe.Translate(trans)) } } validator-10.4.1/translations/ru/000077500000000000000000000000001374261122600167355ustar00rootroot00000000000000validator-10.4.1/translations/ru/ru.go000066400000000000000000001024731374261122600177210ustar00rootroot00000000000000package ru import ( "fmt" "log" "reflect" "strconv" "strings" "time" "github.com/go-playground/locales" ut "github.com/go-playground/universal-translator" "github.com/go-playground/validator/v10" ) // RegisterDefaultTranslations registers a set of default translations // for all built in tag's in validator; you may add your own as desired. func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (err error) { translations := []struct { tag string translation string override bool customRegisFunc validator.RegisterTranslationsFunc customTransFunc validator.TranslationFunc }{ { tag: "required", translation: "{0} обязательное поле", override: false, }, { tag: "len", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("len-string", "{0} должен быть длиной в {1}", false); err != nil { return } if err = ut.AddCardinal("len-string-character", "{0} символ", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("len-string-character", "{0} символы", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("len-number", "{0} должен быть равен {1}", false); err != nil { return } if err = ut.Add("len-items", "{0} должен содержать {1}", false); err != nil { return } if err = ut.AddCardinal("len-items-item", "{0} элемент", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("len-items-item", "{0} элементы", locales.PluralRuleOther, false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var digits uint64 var kind reflect.Kind if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { goto END } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string c, err = ut.C("len-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("len-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string c, err = ut.C("len-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("len-items", fe.Field(), c) default: t, err = ut.T("len-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "min", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("min-string", "{0} должен содержать минимум {1}", false); err != nil { return } if err = ut.AddCardinal("min-string-character", "{0} символ", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("min-string-character", "{0} символы", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("min-number", "{0} должен быть больше или равно {1}", false); err != nil { return } if err = ut.Add("min-items", "{0} должен содержать минимум {1}", false); err != nil { return } if err = ut.AddCardinal("min-items-item", "{0} элемент", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("min-items-item", "{0} элементы", locales.PluralRuleOther, false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var digits uint64 var kind reflect.Kind if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { goto END } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string c, err = ut.C("min-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("min-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string c, err = ut.C("min-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("min-items", fe.Field(), c) default: t, err = ut.T("min-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "max", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("max-string", "{0} должен содержать максимум {1}", false); err != nil { return } if err = ut.AddCardinal("max-string-character", "{0} символ", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("max-string-character", "{0} символы", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("max-number", "{0} должен быть меньше или равно {1}", false); err != nil { return } if err = ut.Add("max-items", "{0} должен содержать максимум {1}", false); err != nil { return } if err = ut.AddCardinal("max-items-item", "{0} элемент", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("max-items-item", "{0} элементы", locales.PluralRuleOther, false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var digits uint64 var kind reflect.Kind if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { goto END } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string c, err = ut.C("max-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("max-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string c, err = ut.C("max-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("max-items", fe.Field(), c) default: t, err = ut.T("max-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "eq", translation: "{0} не равен {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { fmt.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ne", translation: "{0} должен быть не равен {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { fmt.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "lt", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("lt-string", "{0} должен иметь менее {1}", false); err != nil { return } if err = ut.AddCardinal("lt-string-character", "{0} символ", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("lt-string-character", "{0} символы", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lt-number", "{0} должен быть менее {1}", false); err != nil { return } if err = ut.Add("lt-items", "{0} должен содержать менее {1}", false); err != nil { return } if err = ut.AddCardinal("lt-items-item", "{0} элемент", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("lt-items-item", "{0} элементы", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lt-datetime", "{0} must be less than the current Date & Time", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("lt-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lt-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("lt-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lt-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) goto END } t, err = ut.T("lt-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("lt-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "lte", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("lte-string", "{0} должен содержать максимум {1}", false); err != nil { return } if err = ut.AddCardinal("lte-string-character", "{0} символ", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("lte-string-character", "{0} символы", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lte-number", "{0} должен быть менее или равен {1}", false); err != nil { return } if err = ut.Add("lte-items", "{0} должен содержать максимум {1}", false); err != nil { return } if err = ut.AddCardinal("lte-items-item", "{0} элемент", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("lte-items-item", "{0} элементы", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lte-datetime", "{0} must be less than or equal to the current Date & Time", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("lte-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lte-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("lte-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lte-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) goto END } t, err = ut.T("lte-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("lte-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "gt", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("gt-string", "{0} должен быть длиннее {1}", false); err != nil { return } if err = ut.AddCardinal("gt-string-character", "{0} символ", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("gt-string-character", "{0} символы", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gt-number", "{0} должен быть больше {1}", false); err != nil { return } if err = ut.Add("gt-items", "{0} должен содержать более {1}", false); err != nil { return } if err = ut.AddCardinal("gt-items-item", "{0} элемент", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("gt-items-item", "{0} элементы", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gt-datetime", "{0} должна быть позже текущего момента", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("gt-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gt-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("gt-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gt-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) goto END } t, err = ut.T("gt-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("gt-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "gte", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("gte-string", "{0} должен содержать минимум {1}", false); err != nil { return } if err = ut.AddCardinal("gte-string-character", "{0} символ", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("gte-string-character", "{0} символы", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gte-number", "{0} должен быть больше или равно {1}", false); err != nil { return } if err = ut.Add("gte-items", "{0} должен содержать минимум {1}", false); err != nil { return } if err = ut.AddCardinal("gte-items-item", "{0} элемент", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("gte-items-item", "{0} элементы", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gte-datetime", "{0} должна быть позже или равна текущему моменту", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("gte-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gte-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("gte-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gte-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) goto END } t, err = ut.T("gte-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("gte-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "eqfield", translation: "{0} должен быть равен {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "eqcsfield", translation: "{0} должен быть равен {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "necsfield", translation: "{0} не должен быть равен {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtcsfield", translation: "{0} должен быть больше {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtecsfield", translation: "{0} должен быть больше или равен {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltcsfield", translation: "{0} должен быть менее {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltecsfield", translation: "{0} должен быть менее или равен {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "nefield", translation: "{0} не должен быть равен {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtfield", translation: "{0} должен быть больше {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtefield", translation: "{0} должен быть больше или равен {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltfield", translation: "{0} должен быть менее {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltefield", translation: "{0} должен быть менее или равен {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "alpha", translation: "{0} должен содержать только буквы", override: false, }, { tag: "alphanum", translation: "{0} должен содержать только буквы и цифры", override: false, }, { tag: "numeric", translation: "{0} должен быть цифровым значением", override: false, }, { tag: "number", translation: "{0} должен быть цифрой", override: false, }, { tag: "hexadecimal", translation: "{0} должен быть шестнадцатеричной строкой", override: false, }, { tag: "hexcolor", translation: "{0} должен быть HEX цветом", override: false, }, { tag: "rgb", translation: "{0} должен быть RGB цветом", override: false, }, { tag: "rgba", translation: "{0} должен быть RGBA цветом", override: false, }, { tag: "hsl", translation: "{0} должен быть HSL цветом", override: false, }, { tag: "hsla", translation: "{0} должен быть HSLA цветом", override: false, }, { tag: "e164", translation: "{0} должен быть E.164 formatted phone number", override: false, }, { tag: "email", translation: "{0} должен быть email адресом", override: false, }, { tag: "url", translation: "{0} должен быть URL", override: false, }, { tag: "uri", translation: "{0} должен быть URI", override: false, }, { tag: "base64", translation: "{0} должен быть Base64 строкой", override: false, }, { tag: "contains", translation: "{0} должен содержать текст '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "containsany", translation: "{0} должен содержать минимум один из символов '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "excludes", translation: "{0} не должен содержать текст '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "excludesall", translation: "{0} не должен содержать символы '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "excludesrune", translation: "{0} не должен содержать '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "isbn", translation: "{0} должен быть ISBN номером", override: false, }, { tag: "isbn10", translation: "{0} должен быть ISBN-10 номером", override: false, }, { tag: "isbn13", translation: "{0} должен быть ISBN-13 номером", override: false, }, { tag: "uuid", translation: "{0} должен быть UUID", override: false, }, { tag: "uuid3", translation: "{0} должен быть UUID 3 версии", override: false, }, { tag: "uuid4", translation: "{0} должен быть UUID 4 версии", override: false, }, { tag: "uuid5", translation: "{0} должен быть UUID 5 версии", override: false, }, { tag: "ascii", translation: "{0} должен содержать только ascii символы", override: false, }, { tag: "printascii", translation: "{0} должен содержать только доступные для печати ascii символы", override: false, }, { tag: "multibyte", translation: "{0} должен содержать мультибайтные символы", override: false, }, { tag: "datauri", translation: "{0} должен содержать Data URI", override: false, }, { tag: "latitude", translation: "{0} должен содержать координаты широты", override: false, }, { tag: "longitude", translation: "{0} должен содержать координаты долготы", override: false, }, { tag: "ssn", translation: "{0} должен быть SSN номером", override: false, }, { tag: "ipv4", translation: "{0} должен быть IPv4 адресом", override: false, }, { tag: "ipv6", translation: "{0} должен быть IPv6 адресом", override: false, }, { tag: "ip", translation: "{0} должен быть IP адресом", override: false, }, { tag: "cidr", translation: "{0} должен содержать CIDR обозначения", override: false, }, { tag: "cidrv4", translation: "{0} должен содержать CIDR обозначения для IPv4 адреса", override: false, }, { tag: "cidrv6", translation: "{0} должен содержать CIDR обозначения для IPv6 адреса", override: false, }, { tag: "tcp_addr", translation: "{0} должен быть TCP адресом", override: false, }, { tag: "tcp4_addr", translation: "{0} должен быть IPv4 TCP адресом", override: false, }, { tag: "tcp6_addr", translation: "{0} должен быть IPv6 TCP адресом", override: false, }, { tag: "udp_addr", translation: "{0} должен быть UDP адресом", override: false, }, { tag: "udp4_addr", translation: "{0} должен быть IPv4 UDP адресом", override: false, }, { tag: "udp6_addr", translation: "{0} должен быть IPv6 UDP адресом", override: false, }, { tag: "ip_addr", translation: "{0} должен быть распознаваемым IP адресом", override: false, }, { tag: "ip4_addr", translation: "{0} должен быть распознаваемым IPv4 адресом", override: false, }, { tag: "ip6_addr", translation: "{0} должен быть распознаваемым IPv6 адресом", override: false, }, { tag: "unix_addr", translation: "{0} должен быть распознаваемым UNIX адресом", override: false, }, { tag: "mac", translation: "{0} должен содержать MAC адрес", override: false, }, { tag: "unique", translation: "{0} должен содержать уникальные значения", override: false, }, { tag: "iscolor", translation: "{0} должен быть цветом", override: false, }, { tag: "oneof", translation: "{0} должен быть одним из [{1}]", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { s, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return s }, }, } for _, t := range translations { if t.customTransFunc != nil && t.customRegisFunc != nil { err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, t.customTransFunc) } else if t.customTransFunc != nil && t.customRegisFunc == nil { err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), t.customTransFunc) } else if t.customTransFunc == nil && t.customRegisFunc != nil { err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, translateFunc) } else { err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), translateFunc) } if err != nil { return } } return } func registrationFunc(tag string, translation string, override bool) validator.RegisterTranslationsFunc { return func(ut ut.Translator) (err error) { if err = ut.Add(tag, translation, override); err != nil { return } return } } func translateFunc(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t } validator-10.4.1/translations/ru/ru_test.go000066400000000000000000000525551374261122600207650ustar00rootroot00000000000000package ru import ( "log" //"github.com/rustery/validator" "testing" "time" . "github.com/go-playground/assert/v2" russian "github.com/go-playground/locales/en" ut "github.com/go-playground/universal-translator" "github.com/go-playground/validator/v10" ) func TestTranslations(t *testing.T) { ru := russian.New() uni := ut.New(ru, ru) trans, _ := uni.GetTranslator("ru") validate := validator.New() err := RegisterDefaultTranslations(validate, trans) Equal(t, err, nil) type Inner struct { EqCSFieldString string NeCSFieldString string GtCSFieldString string GteCSFieldString string LtCSFieldString string LteCSFieldString string } type Test struct { Inner Inner RequiredString string `validate:"required"` RequiredNumber int `validate:"required"` RequiredMultiple []string `validate:"required"` LenString string `validate:"len=1"` LenNumber float64 `validate:"len=1113.00"` LenMultiple []string `validate:"len=7"` MinString string `validate:"min=1"` MinNumber float64 `validate:"min=1113.00"` MinMultiple []string `validate:"min=7"` MaxString string `validate:"max=3"` MaxNumber float64 `validate:"max=1113.00"` MaxMultiple []string `validate:"max=7"` EqString string `validate:"eq=3"` EqNumber float64 `validate:"eq=2.33"` EqMultiple []string `validate:"eq=7"` NeString string `validate:"ne="` NeNumber float64 `validate:"ne=0.00"` NeMultiple []string `validate:"ne=0"` LtString string `validate:"lt=3"` LtNumber float64 `validate:"lt=5.56"` LtMultiple []string `validate:"lt=2"` LtTime time.Time `validate:"lt"` LteString string `validate:"lte=3"` LteNumber float64 `validate:"lte=5.56"` LteMultiple []string `validate:"lte=2"` LteTime time.Time `validate:"lte"` GtString string `validate:"gt=3"` GtNumber float64 `validate:"gt=5.56"` GtMultiple []string `validate:"gt=2"` GtTime time.Time `validate:"gt"` GteString string `validate:"gte=3"` GteNumber float64 `validate:"gte=5.56"` GteMultiple []string `validate:"gte=2"` GteTime time.Time `validate:"gte"` EqFieldString string `validate:"eqfield=MaxString"` EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"` NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"` GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"` GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"` LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"` LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"` NeFieldString string `validate:"nefield=EqFieldString"` GtFieldString string `validate:"gtfield=MaxString"` GteFieldString string `validate:"gtefield=MaxString"` LtFieldString string `validate:"ltfield=MaxString"` LteFieldString string `validate:"ltefield=MaxString"` AlphaString string `validate:"alpha"` AlphanumString string `validate:"alphanum"` NumericString string `validate:"numeric"` NumberString string `validate:"number"` HexadecimalString string `validate:"hexadecimal"` HexColorString string `validate:"hexcolor"` RGBColorString string `validate:"rgb"` RGBAColorString string `validate:"rgba"` HSLColorString string `validate:"hsl"` HSLAColorString string `validate:"hsla"` Email string `validate:"email"` URL string `validate:"url"` URI string `validate:"uri"` Base64 string `validate:"base64"` Contains string `validate:"contains=purpose"` ContainsAny string `validate:"containsany=!@#$"` Excludes string `validate:"excludes=text"` ExcludesAll string `validate:"excludesall=!@#$"` ExcludesRune string `validate:"excludesrune=☻"` ISBN string `validate:"isbn"` ISBN10 string `validate:"isbn10"` ISBN13 string `validate:"isbn13"` UUID string `validate:"uuid"` UUID3 string `validate:"uuid3"` UUID4 string `validate:"uuid4"` UUID5 string `validate:"uuid5"` ASCII string `validate:"ascii"` PrintableASCII string `validate:"printascii"` MultiByte string `validate:"multibyte"` DataURI string `validate:"datauri"` Latitude string `validate:"latitude"` Longitude string `validate:"longitude"` SSN string `validate:"ssn"` IP string `validate:"ip"` IPv4 string `validate:"ipv4"` IPv6 string `validate:"ipv6"` CIDR string `validate:"cidr"` CIDRv4 string `validate:"cidrv4"` CIDRv6 string `validate:"cidrv6"` TCPAddr string `validate:"tcp_addr"` TCPAddrv4 string `validate:"tcp4_addr"` TCPAddrv6 string `validate:"tcp6_addr"` UDPAddr string `validate:"udp_addr"` UDPAddrv4 string `validate:"udp4_addr"` UDPAddrv6 string `validate:"udp6_addr"` IPAddr string `validate:"ip_addr"` IPAddrv4 string `validate:"ip4_addr"` IPAddrv6 string `validate:"ip6_addr"` UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future MAC string `validate:"mac"` IsColor string `validate:"iscolor"` StrPtrMinLen *string `validate:"min=10"` StrPtrMaxLen *string `validate:"max=1"` StrPtrLen *string `validate:"len=2"` StrPtrLt *string `validate:"lt=1"` StrPtrLte *string `validate:"lte=1"` StrPtrGt *string `validate:"gt=10"` StrPtrGte *string `validate:"gte=10"` OneOfString string `validate:"oneof=red green"` OneOfInt int `validate:"oneof=5 63"` UniqueSlice []string `validate:"unique"` UniqueArray [3]string `validate:"unique"` UniqueMap map[string]string `validate:"unique"` } var test Test test.Inner.EqCSFieldString = "1234" test.Inner.GtCSFieldString = "1234" test.Inner.GteCSFieldString = "1234" test.MaxString = "1234" test.MaxNumber = 2000 test.MaxMultiple = make([]string, 9) test.LtString = "1234" test.LtNumber = 6 test.LtMultiple = make([]string, 3) test.LtTime = time.Now().Add(time.Hour * 24) test.LteString = "1234" test.LteNumber = 6 test.LteMultiple = make([]string, 3) test.LteTime = time.Now().Add(time.Hour * 24) test.LtFieldString = "12345" test.LteFieldString = "12345" test.LtCSFieldString = "1234" test.LteCSFieldString = "1234" test.AlphaString = "abc3" test.AlphanumString = "abc3!" test.NumericString = "12E.00" test.NumberString = "12E" test.Excludes = "this is some test text" test.ExcludesAll = "This is Great!" test.ExcludesRune = "Love it ☻" test.ASCII = "カタカナ" test.PrintableASCII = "カタカナ" test.MultiByte = "1234feerf" s := "toolong" test.StrPtrMaxLen = &s test.StrPtrLen = &s test.UniqueSlice = []string{"1234", "1234"} test.UniqueMap = map[string]string{"key1": "1234", "key2": "1234"} err = validate.Struct(test) NotEqual(t, err, nil) errs, ok := err.(validator.ValidationErrors) Equal(t, ok, true) tests := []struct { ns string expected string }{ { ns: "Test.IsColor", expected: "IsColor должен быть цветом", }, { ns: "Test.MAC", expected: "MAC должен содержать MAC адрес", }, { ns: "Test.IPAddr", expected: "IPAddr должен быть распознаваемым IP адресом", }, { ns: "Test.IPAddrv4", expected: "IPAddrv4 должен быть распознаваемым IPv4 адресом", }, { ns: "Test.IPAddrv6", expected: "IPAddrv6 должен быть распознаваемым IPv6 адресом", }, { ns: "Test.UDPAddr", expected: "UDPAddr должен быть UDP адресом", }, { ns: "Test.UDPAddrv4", expected: "UDPAddrv4 должен быть IPv4 UDP адресом", }, { ns: "Test.UDPAddrv6", expected: "UDPAddrv6 должен быть IPv6 UDP адресом", }, { ns: "Test.TCPAddr", expected: "TCPAddr должен быть TCP адресом", }, { ns: "Test.TCPAddrv4", expected: "TCPAddrv4 должен быть IPv4 TCP адресом", }, { ns: "Test.TCPAddrv6", expected: "TCPAddrv6 должен быть IPv6 TCP адресом", }, { ns: "Test.CIDR", expected: "CIDR должен содержать CIDR обозначения", }, { ns: "Test.CIDRv4", expected: "CIDRv4 должен содержать CIDR обозначения для IPv4 адреса", }, { ns: "Test.CIDRv6", expected: "CIDRv6 должен содержать CIDR обозначения для IPv6 адреса", }, { ns: "Test.SSN", expected: "SSN должен быть SSN номером", }, { ns: "Test.IP", expected: "IP должен быть IP адресом", }, { ns: "Test.IPv4", expected: "IPv4 должен быть IPv4 адресом", }, { ns: "Test.IPv6", expected: "IPv6 должен быть IPv6 адресом", }, { ns: "Test.DataURI", expected: "DataURI должен содержать Data URI", }, { ns: "Test.Latitude", expected: "Latitude должен содержать координаты широты", }, { ns: "Test.Longitude", expected: "Longitude должен содержать координаты долготы", }, { ns: "Test.MultiByte", expected: "MultiByte должен содержать мультибайтные символы", }, { ns: "Test.ASCII", expected: "ASCII должен содержать только ascii символы", }, { ns: "Test.PrintableASCII", expected: "PrintableASCII должен содержать только доступные для печати ascii символы", }, { ns: "Test.UUID", expected: "UUID должен быть UUID", }, { ns: "Test.UUID3", expected: "UUID3 должен быть UUID 3 версии", }, { ns: "Test.UUID4", expected: "UUID4 должен быть UUID 4 версии", }, { ns: "Test.UUID5", expected: "UUID5 должен быть UUID 5 версии", }, { ns: "Test.ISBN", expected: "ISBN должен быть ISBN номером", }, { ns: "Test.ISBN10", expected: "ISBN10 должен быть ISBN-10 номером", }, { ns: "Test.ISBN13", expected: "ISBN13 должен быть ISBN-13 номером", }, { ns: "Test.Excludes", expected: "Excludes не должен содержать текст 'text'", }, { ns: "Test.ExcludesAll", expected: "ExcludesAll не должен содержать символы '!@#$'", }, { ns: "Test.ExcludesRune", expected: "ExcludesRune не должен содержать '☻'", }, { ns: "Test.ContainsAny", expected: "ContainsAny должен содержать минимум один из символов '!@#$'", }, { ns: "Test.Contains", expected: "Contains должен содержать текст 'purpose'", }, { ns: "Test.Base64", expected: "Base64 должен быть Base64 строкой", }, { ns: "Test.Email", expected: "Email должен быть email адресом", }, { ns: "Test.URL", expected: "URL должен быть URL", }, { ns: "Test.URI", expected: "URI должен быть URI", }, { ns: "Test.RGBColorString", expected: "RGBColorString должен быть RGB цветом", }, { ns: "Test.RGBAColorString", expected: "RGBAColorString должен быть RGBA цветом", }, { ns: "Test.HSLColorString", expected: "HSLColorString должен быть HSL цветом", }, { ns: "Test.HSLAColorString", expected: "HSLAColorString должен быть HSLA цветом", }, { ns: "Test.HexadecimalString", expected: "HexadecimalString должен быть шестнадцатеричной строкой", }, { ns: "Test.HexColorString", expected: "HexColorString должен быть HEX цветом", }, { ns: "Test.NumberString", expected: "NumberString должен быть цифрой", }, { ns: "Test.NumericString", expected: "NumericString должен быть цифровым значением", }, { ns: "Test.AlphanumString", expected: "AlphanumString должен содержать только буквы и цифры", }, { ns: "Test.AlphaString", expected: "AlphaString должен содержать только буквы", }, { ns: "Test.LtFieldString", expected: "LtFieldString должен быть менее MaxString", }, { ns: "Test.LteFieldString", expected: "LteFieldString должен быть менее или равен MaxString", }, { ns: "Test.GtFieldString", expected: "GtFieldString должен быть больше MaxString", }, { ns: "Test.GteFieldString", expected: "GteFieldString должен быть больше или равен MaxString", }, { ns: "Test.NeFieldString", expected: "NeFieldString не должен быть равен EqFieldString", }, { ns: "Test.LtCSFieldString", expected: "LtCSFieldString должен быть менее Inner.LtCSFieldString", }, { ns: "Test.LteCSFieldString", expected: "LteCSFieldString должен быть менее или равен Inner.LteCSFieldString", }, { ns: "Test.GtCSFieldString", expected: "GtCSFieldString должен быть больше Inner.GtCSFieldString", }, { ns: "Test.GteCSFieldString", expected: "GteCSFieldString должен быть больше или равен Inner.GteCSFieldString", }, { ns: "Test.NeCSFieldString", expected: "NeCSFieldString не должен быть равен Inner.NeCSFieldString", }, { ns: "Test.EqCSFieldString", expected: "EqCSFieldString должен быть равен Inner.EqCSFieldString", }, { ns: "Test.EqFieldString", expected: "EqFieldString должен быть равен MaxString", }, { ns: "Test.GteString", expected: "GteString должен содержать минимум 3 символы", }, { ns: "Test.GteNumber", expected: "GteNumber должен быть больше или равно 5.56", }, { ns: "Test.GteMultiple", expected: "GteMultiple должен содержать минимум 2 элементы", }, { ns: "Test.GteTime", expected: "GteTime должна быть позже или равна текущему моменту", }, { ns: "Test.GtString", expected: "GtString должен быть длиннее 3 символы", }, { ns: "Test.GtNumber", expected: "GtNumber должен быть больше 5.56", }, { ns: "Test.GtMultiple", expected: "GtMultiple должен содержать более 2 элементы", }, { ns: "Test.GtTime", expected: "GtTime должна быть позже текущего момента", }, { ns: "Test.LteString", expected: "LteString должен содержать максимум 3 символы", }, { ns: "Test.LteNumber", expected: "LteNumber должен быть менее или равен 5.56", }, { ns: "Test.LteMultiple", expected: "LteMultiple должен содержать максимум 2 элементы", }, { ns: "Test.LteTime", expected: "LteTime must be less than or equal to the current Date & Time", }, { ns: "Test.LtString", expected: "LtString должен иметь менее 3 символы", }, { ns: "Test.LtNumber", expected: "LtNumber должен быть менее 5.56", }, { ns: "Test.LtMultiple", expected: "LtMultiple должен содержать менее 2 элементы", }, { ns: "Test.LtTime", expected: "LtTime must be less than the current Date & Time", }, { ns: "Test.NeString", expected: "NeString должен быть не равен ", }, { ns: "Test.NeNumber", expected: "NeNumber должен быть не равен 0.00", }, { ns: "Test.NeMultiple", expected: "NeMultiple должен быть не равен 0", }, { ns: "Test.EqString", expected: "EqString не равен 3", }, { ns: "Test.EqNumber", expected: "EqNumber не равен 2.33", }, { ns: "Test.EqMultiple", expected: "EqMultiple не равен 7", }, { ns: "Test.MaxString", expected: "MaxString должен содержать максимум 3 символы", }, { ns: "Test.MaxNumber", expected: "MaxNumber должен быть меньше или равно 1,113.00", }, { ns: "Test.MaxMultiple", expected: "MaxMultiple должен содержать максимум 7 элементы", }, { ns: "Test.MinString", expected: "MinString должен содержать минимум 1 символ", }, { ns: "Test.MinNumber", expected: "MinNumber должен быть больше или равно 1,113.00", }, { ns: "Test.MinMultiple", expected: "MinMultiple должен содержать минимум 7 элементы", }, { ns: "Test.LenString", expected: "LenString должен быть длиной в 1 символ", }, { ns: "Test.LenNumber", expected: "LenNumber должен быть равен 1,113.00", }, { ns: "Test.LenMultiple", expected: "LenMultiple должен содержать 7 элементы", }, { ns: "Test.RequiredString", expected: "RequiredString обязательное поле", }, { ns: "Test.RequiredNumber", expected: "RequiredNumber обязательное поле", }, { ns: "Test.RequiredMultiple", expected: "RequiredMultiple обязательное поле", }, { ns: "Test.StrPtrMinLen", expected: "StrPtrMinLen должен содержать минимум 10 символы", }, { ns: "Test.StrPtrMaxLen", expected: "StrPtrMaxLen должен содержать максимум 1 символ", }, { ns: "Test.StrPtrLen", expected: "StrPtrLen должен быть длиной в 2 символы", }, { ns: "Test.StrPtrLt", expected: "StrPtrLt должен иметь менее 1 символ", }, { ns: "Test.StrPtrLte", expected: "StrPtrLte должен содержать максимум 1 символ", }, { ns: "Test.StrPtrGt", expected: "StrPtrGt должен быть длиннее 10 символы", }, { ns: "Test.StrPtrGte", expected: "StrPtrGte должен содержать минимум 10 символы", }, { ns: "Test.OneOfString", expected: "OneOfString должен быть одним из [red green]", }, { ns: "Test.OneOfInt", expected: "OneOfInt должен быть одним из [5 63]", }, { ns: "Test.UniqueSlice", expected: "UniqueSlice должен содержать уникальные значения", }, { ns: "Test.UniqueArray", expected: "UniqueArray должен содержать уникальные значения", }, { ns: "Test.UniqueMap", expected: "UniqueMap должен содержать уникальные значения", }, } for _, tt := range tests { var fe validator.FieldError for _, e := range errs { if tt.ns == e.Namespace() { fe = e break } } log.Println(fe) NotEqual(t, fe, nil) Equal(t, tt.expected, fe.Translate(trans)) } } validator-10.4.1/translations/tr/000077500000000000000000000000001374261122600167345ustar00rootroot00000000000000validator-10.4.1/translations/tr/tr.go000066400000000000000000000776371374261122600177340ustar00rootroot00000000000000package tr import ( "fmt" "log" "reflect" "strconv" "strings" "time" "github.com/go-playground/locales" ut "github.com/go-playground/universal-translator" "github.com/go-playground/validator/v10" ) // RegisterDefaultTranslations registers a set of default translations // for all built in tag's in validator; you may add your own as desired. func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (err error) { translations := []struct { tag string translation string override bool customRegisFunc validator.RegisterTranslationsFunc customTransFunc validator.TranslationFunc }{ { tag: "required", translation: "{0} zorunlu bir alandır", override: false, }, { tag: "len", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("len-string", "{0} uzunluğu {1} olmalıdır", false); err != nil { return } if err = ut.AddCardinal("len-string-character", "{0} karakter", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("len-string-character", "{0} karakter", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("len-number", "{0}, {1} değerine eşit olmalıdır", false); err != nil { return } if err = ut.Add("len-items", "{0}, {1} içermelidir", false); err != nil { return } if err = ut.AddCardinal("len-items-item", "{0} öğe", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("len-items-item", "{0} öğe", locales.PluralRuleOther, false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var digits uint64 var kind reflect.Kind if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { goto END } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string c, err = ut.C("len-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("len-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string c, err = ut.C("len-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("len-items", fe.Field(), c) default: t, err = ut.T("len-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "min", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("min-string", "{0} en az {1} uzunluğunda olmalıdır", false); err != nil { return } if err = ut.AddCardinal("min-string-character", "{0} karakter", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("min-string-character", "{0} karakter", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("min-number", "{0}, {1} veya daha büyük olmalıdır", false); err != nil { return } if err = ut.Add("min-items", "{0} en az {1} içermelidir", false); err != nil { return } if err = ut.AddCardinal("min-items-item", "{0} öğe", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("min-items-item", "{0} öğe", locales.PluralRuleOther, false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var digits uint64 var kind reflect.Kind if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { goto END } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string c, err = ut.C("min-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("min-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string c, err = ut.C("min-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("min-items", fe.Field(), c) default: t, err = ut.T("min-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "max", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("max-string", "{0} uzunluğu en fazla {1} olmalıdır", false); err != nil { return } if err = ut.AddCardinal("max-string-character", "{0} karakter", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("max-string-character", "{0} karakter", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("max-number", "{0}, {1} veya daha az olmalıdır", false); err != nil { return } if err = ut.Add("max-items", "{0} maksimum {1} içermelidir", false); err != nil { return } if err = ut.AddCardinal("max-items-item", "{0} öğe", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("max-items-item", "{0} öğe", locales.PluralRuleOther, false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var digits uint64 var kind reflect.Kind if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { goto END } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string c, err = ut.C("max-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("max-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string c, err = ut.C("max-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("max-items", fe.Field(), c) default: t, err = ut.T("max-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "eq", translation: "{0}, {1} değerine eşit değil", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { fmt.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ne", translation: "{0}, {1} değerine eşit olmamalıdır", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { fmt.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "lt", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("lt-string", "{0}, {1} uzunluğundan daha az olmalıdır", false); err != nil { return } if err = ut.AddCardinal("lt-string-character", "{0} karakter", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("lt-string-character", "{0} karakter", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lt-number", "{0}, {1} değerinden küçük olmalıdır", false); err != nil { return } if err = ut.Add("lt-items", "{0}, {1}den daha az içermelidir", false); err != nil { return } if err = ut.AddCardinal("lt-items-item", "{0} öğe", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("lt-items-item", "{0} öğe", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lt-datetime", "{0} geçerli Tarih ve Saatten daha az olmalıdır", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("lt-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lt-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("lt-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lt-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) goto END } t, err = ut.T("lt-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("lt-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "lte", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("lte-string", "{0} en fazla {1} uzunluğunda olmalıdır", false); err != nil { return } if err = ut.AddCardinal("lte-string-character", "{0} karakter", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("lte-string-character", "{0} karakter", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lte-number", "{0}, {1} veya daha az olmalıdır", false); err != nil { return } if err = ut.Add("lte-items", "{0}, maksimum {1} içermelidir", false); err != nil { return } if err = ut.AddCardinal("lte-items-item", "{0} öğe", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("lte-items-item", "{0} öğe", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lte-datetime", "{0} geçerli Tarih ve Saate eşit veya daha küçük olmalıdır", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("lte-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lte-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("lte-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lte-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) goto END } t, err = ut.T("lte-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("lte-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "gt", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("gt-string", "{0}, {1} uzunluğundan fazla olmalıdır", false); err != nil { return } if err = ut.AddCardinal("gt-string-character", "{0} karakter", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("gt-string-character", "{0} karakter", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gt-number", "{0}, {1} değerinden büyük olmalıdır", false); err != nil { return } if err = ut.Add("gt-items", "{0}, {1}den daha fazla içermelidir", false); err != nil { return } if err = ut.AddCardinal("gt-items-item", "{0} öğe", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("gt-items-item", "{0} öğe", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gt-datetime", "{0} geçerli Tarih ve Saatten büyük olmalıdır", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("gt-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gt-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("gt-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gt-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) goto END } t, err = ut.T("gt-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("gt-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "gte", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("gte-string", "{0} en az {1} uzunluğunda olmalıdır", false); err != nil { return } if err = ut.AddCardinal("gte-string-character", "{0} karakter", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("gte-string-character", "{0} karakter", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gte-number", "{0}, {1} veya daha büyük olmalıdır", false); err != nil { return } if err = ut.Add("gte-items", "{0} en az {1} içermelidir", false); err != nil { return } if err = ut.AddCardinal("gte-items-item", "{0} öğe", locales.PluralRuleOne, false); err != nil { return } if err = ut.AddCardinal("gte-items-item", "{0} öğe", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gte-datetime", "{0} geçerli Tarih ve Saatten büyük veya ona eşit olmalıdır", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("gte-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gte-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("gte-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gte-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) goto END } t, err = ut.T("gte-datetime", fe.Field()) default: err = fn() if err != nil { goto END } t, err = ut.T("gte-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } return t }, }, { tag: "eqfield", translation: "{0}, {1} değerine eşit olmalıdır", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "eqcsfield", translation: "{0}, {1} değerine eşit olmalıdır", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "necsfield", translation: "{0}, {1} değerine eşit olmamalıdır", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtcsfield", translation: "{0}, {1} değerinden büyük olmalıdır", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtecsfield", translation: "{0}, {1} değerinden küçük veya ona eşit olmalıdır", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltcsfield", translation: "{0}, {1} değerinden küçük olmalıdır", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltecsfield", translation: "{0}, {1} değerinden küçük veya ona eşit olmalıdır", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "nefield", translation: "{0}, {1} değerine eşit olmamalıdır", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtfield", translation: "{0}, {1} değerinden büyük olmalıdır", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtefield", translation: "{0}, {1} değerinden büyük veya ona eşit olmalıdır", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltfield", translation: "{0}, {1} değerinden küçük olmalıdır", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltefield", translation: "{0}, {1} değerinden küçük veya ona eşit olmalıdır", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "alpha", translation: "{0} yalnızca alfabetik karakterler içerebilir", override: false, }, { tag: "alphanum", translation: "{0} yalnızca alfanümerik karakterler içerebilir", override: false, }, { tag: "numeric", translation: "{0} geçerli bir sayısal değer olmalıdır", override: false, }, { tag: "number", translation: "{0} geçerli bir sayı olmalıdır", override: false, }, { tag: "hexadecimal", translation: "{0} geçerli bir onaltılık olmalıdır", override: false, }, { tag: "hexcolor", translation: "{0} geçerli bir HEX rengi olmalıdır", override: false, }, { tag: "rgb", translation: "{0} geçerli bir RGB rengi olmalıdır", override: false, }, { tag: "rgba", translation: "{0} geçerli bir RGBA rengi olmalıdır", override: false, }, { tag: "hsl", translation: "{0} geçerli bir HSL rengi olmalıdır", override: false, }, { tag: "hsla", translation: "{0} geçerli bir HSLA rengi olmalıdır", override: false, }, { tag: "email", translation: "{0} geçerli bir e-posta adresi olmalıdır", override: false, }, { tag: "url", translation: "{0} geçerli bir URL olmalıdır", override: false, }, { tag: "uri", translation: "{0} geçerli bir URI olmalıdır", override: false, }, { tag: "base64", translation: "{0} geçerli bir Base64 karakter dizesi olmalıdır", override: false, }, { tag: "contains", translation: "{0}, '{1}' metnini içermelidir", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "containsany", translation: "{0}, '{1}' karakterlerinden en az birini içermelidir", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "excludes", translation: "{0}, '{1}' metnini içeremez", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "excludesall", translation: "{0}, '{1}' karakterlerinden hiçbirini içeremez", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "excludesrune", translation: "{0}, '{1}' ifadesini içeremez", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "isbn", translation: "{0} geçerli bir ISBN numarası olmalıdır", override: false, }, { tag: "isbn10", translation: "{0} geçerli bir ISBN-10 numarası olmalıdır", override: false, }, { tag: "isbn13", translation: "{0} geçerli bir ISBN-13 numarası olmalıdır", override: false, }, { tag: "uuid", translation: "{0} geçerli bir UUID olmalıdır", override: false, }, { tag: "uuid3", translation: "{0} geçerli bir sürüm 3 UUID olmalıdır", override: false, }, { tag: "uuid4", translation: "{0} geçerli bir sürüm 4 UUID olmalıdır", override: false, }, { tag: "uuid5", translation: "{0} geçerli bir sürüm 5 UUID olmalıdır", override: false, }, { tag: "ascii", translation: "{0} yalnızca ascii karakterler içermelidir", override: false, }, { tag: "printascii", translation: "{0} yalnızca yazdırılabilir ascii karakterleri içermelidir", override: false, }, { tag: "multibyte", translation: "{0} çok baytlı karakterler içermelidir", override: false, }, { tag: "datauri", translation: "{0} geçerli bir Veri URI içermelidir", override: false, }, { tag: "latitude", translation: "{0} geçerli bir enlem koordinatı içermelidir", override: false, }, { tag: "longitude", translation: "{0} geçerli bir boylam koordinatı içermelidir", override: false, }, { tag: "ssn", translation: "{0} geçerli bir SSN numarası olmalıdır", override: false, }, { tag: "ipv4", translation: "{0} geçerli bir IPv4 adresi olmalıdır", override: false, }, { tag: "ipv6", translation: "{0} geçerli bir IPv6 adresi olmalıdır", override: false, }, { tag: "ip", translation: "{0} geçerli bir IP adresi olmalıdır", override: false, }, { tag: "cidr", translation: "{0} geçerli bir CIDR gösterimi içermelidir", override: false, }, { tag: "cidrv4", translation: "{0} bir IPv4 adresi için geçerli bir CIDR gösterimi içermelidir", override: false, }, { tag: "cidrv6", translation: "{0} bir IPv6 adresi için geçerli bir CIDR gösterimi içermelidir", override: false, }, { tag: "tcp_addr", translation: "{0} geçerli bir TCP adresi olmalıdır", override: false, }, { tag: "tcp4_addr", translation: "{0} geçerli bir IPv4 TCP adresi olmalıdır", override: false, }, { tag: "tcp6_addr", translation: "{0} geçerli bir IPv6 TCP adresi olmalıdır", override: false, }, { tag: "udp_addr", translation: "{0} geçerli bir UDP adresi olmalıdır", override: false, }, { tag: "udp4_addr", translation: "{0} geçerli bir IPv4 UDP adresi olmalıdır", override: false, }, { tag: "udp6_addr", translation: "{0} geçerli bir IPv6 UDP adresi olmalıdır", override: false, }, { tag: "ip_addr", translation: "{0} çözülebilir bir IP adresi olmalıdır", override: false, }, { tag: "ip4_addr", translation: "{0} çözülebilir bir IPv4 adresi olmalıdır", override: false, }, { tag: "ip6_addr", translation: "{0} çözülebilir bir IPv6 adresi olmalıdır", override: false, }, { tag: "unix_addr", translation: "{0} çözülebilir bir UNIX adresi olmalıdır", override: false, }, { tag: "mac", translation: "{0} geçerli bir MAC adresi içermelidir", override: false, }, { tag: "unique", translation: "{0} benzersiz değerler içermelidir", override: false, }, { tag: "iscolor", translation: "{0} geçerli bir renk olmalıdır", override: false, }, { tag: "oneof", translation: "{0}, [{1}]'dan biri olmalıdır", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { s, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return s }, }, } for _, t := range translations { if t.customTransFunc != nil && t.customRegisFunc != nil { err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, t.customTransFunc) } else if t.customTransFunc != nil && t.customRegisFunc == nil { err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), t.customTransFunc) } else if t.customTransFunc == nil && t.customRegisFunc != nil { err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, translateFunc) } else { err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), translateFunc) } if err != nil { return } } return } func registrationFunc(tag string, translation string, override bool) validator.RegisterTranslationsFunc { return func(ut ut.Translator) (err error) { if err = ut.Add(tag, translation, override); err != nil { return } return } } func translateFunc(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } return t } validator-10.4.1/translations/tr/tr_test.go000066400000000000000000000476471374261122600207710ustar00rootroot00000000000000package tr import ( "testing" "time" turkish "github.com/go-playground/locales/tr" ut "github.com/go-playground/universal-translator" . "github.com/go-playground/assert/v2" "github.com/go-playground/validator/v10" ) func TestTranslations(t *testing.T) { tr := turkish.New() uni := ut.New(tr, tr) trans, _ := uni.GetTranslator("tr") validate := validator.New() err := RegisterDefaultTranslations(validate, trans) Equal(t, err, nil) type Inner struct { EqCSFieldString string NeCSFieldString string GtCSFieldString string GteCSFieldString string LtCSFieldString string LteCSFieldString string } type Test struct { Inner Inner RequiredString string `validate:"required"` RequiredNumber int `validate:"required"` RequiredMultiple []string `validate:"required"` LenString string `validate:"len=1"` LenNumber float64 `validate:"len=1113.00"` LenMultiple []string `validate:"len=7"` MinString string `validate:"min=1"` MinNumber float64 `validate:"min=1113.00"` MinMultiple []string `validate:"min=7"` MaxString string `validate:"max=3"` MaxNumber float64 `validate:"max=1113.00"` MaxMultiple []string `validate:"max=7"` EqString string `validate:"eq=3"` EqNumber float64 `validate:"eq=2.33"` EqMultiple []string `validate:"eq=7"` NeString string `validate:"ne="` NeNumber float64 `validate:"ne=0.00"` NeMultiple []string `validate:"ne=0"` LtString string `validate:"lt=3"` LtNumber float64 `validate:"lt=5.56"` LtMultiple []string `validate:"lt=2"` LtTime time.Time `validate:"lt"` LteString string `validate:"lte=3"` LteNumber float64 `validate:"lte=5.56"` LteMultiple []string `validate:"lte=2"` LteTime time.Time `validate:"lte"` GtString string `validate:"gt=3"` GtNumber float64 `validate:"gt=5.56"` GtMultiple []string `validate:"gt=2"` GtTime time.Time `validate:"gt"` GteString string `validate:"gte=3"` GteNumber float64 `validate:"gte=5.56"` GteMultiple []string `validate:"gte=2"` GteTime time.Time `validate:"gte"` EqFieldString string `validate:"eqfield=MaxString"` EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"` NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"` GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"` GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"` LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"` LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"` NeFieldString string `validate:"nefield=EqFieldString"` GtFieldString string `validate:"gtfield=MaxString"` GteFieldString string `validate:"gtefield=MaxString"` LtFieldString string `validate:"ltfield=MaxString"` LteFieldString string `validate:"ltefield=MaxString"` AlphaString string `validate:"alpha"` AlphanumString string `validate:"alphanum"` NumericString string `validate:"numeric"` NumberString string `validate:"number"` HexadecimalString string `validate:"hexadecimal"` HexColorString string `validate:"hexcolor"` RGBColorString string `validate:"rgb"` RGBAColorString string `validate:"rgba"` HSLColorString string `validate:"hsl"` HSLAColorString string `validate:"hsla"` Email string `validate:"email"` URL string `validate:"url"` URI string `validate:"uri"` Base64 string `validate:"base64"` Contains string `validate:"contains=purpose"` ContainsAny string `validate:"containsany=!@#$"` Excludes string `validate:"excludes=text"` ExcludesAll string `validate:"excludesall=!@#$"` ExcludesRune string `validate:"excludesrune=☻"` ISBN string `validate:"isbn"` ISBN10 string `validate:"isbn10"` ISBN13 string `validate:"isbn13"` UUID string `validate:"uuid"` UUID3 string `validate:"uuid3"` UUID4 string `validate:"uuid4"` UUID5 string `validate:"uuid5"` ASCII string `validate:"ascii"` PrintableASCII string `validate:"printascii"` MultiByte string `validate:"multibyte"` DataURI string `validate:"datauri"` Latitude string `validate:"latitude"` Longitude string `validate:"longitude"` SSN string `validate:"ssn"` IP string `validate:"ip"` IPv4 string `validate:"ipv4"` IPv6 string `validate:"ipv6"` CIDR string `validate:"cidr"` CIDRv4 string `validate:"cidrv4"` CIDRv6 string `validate:"cidrv6"` TCPAddr string `validate:"tcp_addr"` TCPAddrv4 string `validate:"tcp4_addr"` TCPAddrv6 string `validate:"tcp6_addr"` UDPAddr string `validate:"udp_addr"` UDPAddrv4 string `validate:"udp4_addr"` UDPAddrv6 string `validate:"udp6_addr"` IPAddr string `validate:"ip_addr"` IPAddrv4 string `validate:"ip4_addr"` IPAddrv6 string `validate:"ip6_addr"` UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future MAC string `validate:"mac"` IsColor string `validate:"iscolor"` StrPtrMinLen *string `validate:"min=10"` StrPtrMaxLen *string `validate:"max=1"` StrPtrLen *string `validate:"len=2"` StrPtrLt *string `validate:"lt=1"` StrPtrLte *string `validate:"lte=1"` StrPtrGt *string `validate:"gt=10"` StrPtrGte *string `validate:"gte=10"` OneOfString string `validate:"oneof=red green"` OneOfInt int `validate:"oneof=5 63"` UniqueSlice []string `validate:"unique"` UniqueArray [3]string `validate:"unique"` UniqueMap map[string]string `validate:"unique"` } var test Test test.Inner.EqCSFieldString = "1234" test.Inner.GtCSFieldString = "1234" test.Inner.GteCSFieldString = "1234" test.MaxString = "1234" test.MaxNumber = 2000 test.MaxMultiple = make([]string, 9) test.LtString = "1234" test.LtNumber = 6 test.LtMultiple = make([]string, 3) test.LtTime = time.Now().Add(time.Hour * 24) test.LteString = "1234" test.LteNumber = 6 test.LteMultiple = make([]string, 3) test.LteTime = time.Now().Add(time.Hour * 24) test.LtFieldString = "12345" test.LteFieldString = "12345" test.LtCSFieldString = "1234" test.LteCSFieldString = "1234" test.AlphaString = "abc3" test.AlphanumString = "abc3!" test.NumericString = "12E.00" test.NumberString = "12E" test.Excludes = "this is some test text" test.ExcludesAll = "This is Great!" test.ExcludesRune = "Love it ☻" test.ASCII = "カタカナ" test.PrintableASCII = "カタカナ" test.MultiByte = "1234feerf" s := "toolong" test.StrPtrMaxLen = &s test.StrPtrLen = &s test.UniqueSlice = []string{"1234", "1234"} test.UniqueMap = map[string]string{"key1": "1234", "key2": "1234"} err = validate.Struct(test) NotEqual(t, err, nil) errs, ok := err.(validator.ValidationErrors) Equal(t, ok, true) tests := []struct { ns string expected string }{ { ns: "Test.IsColor", expected: "IsColor geçerli bir renk olmalıdır", }, { ns: "Test.MAC", expected: "MAC geçerli bir MAC adresi içermelidir", }, { ns: "Test.IPAddr", expected: "IPAddr çözülebilir bir IP adresi olmalıdır", }, { ns: "Test.IPAddrv4", expected: "IPAddrv4 çözülebilir bir IPv4 adresi olmalıdır", }, { ns: "Test.IPAddrv6", expected: "IPAddrv6 çözülebilir bir IPv6 adresi olmalıdır", }, { ns: "Test.UDPAddr", expected: "UDPAddr geçerli bir UDP adresi olmalıdır", }, { ns: "Test.UDPAddrv4", expected: "UDPAddrv4 geçerli bir IPv4 UDP adresi olmalıdır", }, { ns: "Test.UDPAddrv6", expected: "UDPAddrv6 geçerli bir IPv6 UDP adresi olmalıdır", }, { ns: "Test.TCPAddr", expected: "TCPAddr geçerli bir TCP adresi olmalıdır", }, { ns: "Test.TCPAddrv4", expected: "TCPAddrv4 geçerli bir IPv4 TCP adresi olmalıdır", }, { ns: "Test.TCPAddrv6", expected: "TCPAddrv6 geçerli bir IPv6 TCP adresi olmalıdır", }, { ns: "Test.CIDR", expected: "CIDR geçerli bir CIDR gösterimi içermelidir", }, { ns: "Test.CIDRv4", expected: "CIDRv4 bir IPv4 adresi için geçerli bir CIDR gösterimi içermelidir", }, { ns: "Test.CIDRv6", expected: "CIDRv6 bir IPv6 adresi için geçerli bir CIDR gösterimi içermelidir", }, { ns: "Test.SSN", expected: "SSN geçerli bir SSN numarası olmalıdır", }, { ns: "Test.IP", expected: "IP geçerli bir IP adresi olmalıdır", }, { ns: "Test.IPv4", expected: "IPv4 geçerli bir IPv4 adresi olmalıdır", }, { ns: "Test.IPv6", expected: "IPv6 geçerli bir IPv6 adresi olmalıdır", }, { ns: "Test.DataURI", expected: "DataURI geçerli bir Veri URI içermelidir", }, { ns: "Test.Latitude", expected: "Latitude geçerli bir enlem koordinatı içermelidir", }, { ns: "Test.Longitude", expected: "Longitude geçerli bir boylam koordinatı içermelidir", }, { ns: "Test.MultiByte", expected: "MultiByte çok baytlı karakterler içermelidir", }, { ns: "Test.ASCII", expected: "ASCII yalnızca ascii karakterler içermelidir", }, { ns: "Test.PrintableASCII", expected: "PrintableASCII yalnızca yazdırılabilir ascii karakterleri içermelidir", }, { ns: "Test.UUID", expected: "UUID geçerli bir UUID olmalıdır", }, { ns: "Test.UUID3", expected: "UUID3 geçerli bir sürüm 3 UUID olmalıdır", }, { ns: "Test.UUID4", expected: "UUID4 geçerli bir sürüm 4 UUID olmalıdır", }, { ns: "Test.UUID5", expected: "UUID5 geçerli bir sürüm 5 UUID olmalıdır", }, { ns: "Test.ISBN", expected: "ISBN geçerli bir ISBN numarası olmalıdır", }, { ns: "Test.ISBN10", expected: "ISBN10 geçerli bir ISBN-10 numarası olmalıdır", }, { ns: "Test.ISBN13", expected: "ISBN13 geçerli bir ISBN-13 numarası olmalıdır", }, { ns: "Test.Excludes", expected: "Excludes, 'text' metnini içeremez", }, { ns: "Test.ExcludesAll", expected: "ExcludesAll, '!@#$' karakterlerinden hiçbirini içeremez", }, { ns: "Test.ExcludesRune", expected: "ExcludesRune, '☻' ifadesini içeremez", }, { ns: "Test.ContainsAny", expected: "ContainsAny, '!@#$' karakterlerinden en az birini içermelidir", }, { ns: "Test.Contains", expected: "Contains, 'purpose' metnini içermelidir", }, { ns: "Test.Base64", expected: "Base64 geçerli bir Base64 karakter dizesi olmalıdır", }, { ns: "Test.Email", expected: "Email geçerli bir e-posta adresi olmalıdır", }, { ns: "Test.URL", expected: "URL geçerli bir URL olmalıdır", }, { ns: "Test.URI", expected: "URI geçerli bir URI olmalıdır", }, { ns: "Test.RGBColorString", expected: "RGBColorString geçerli bir RGB rengi olmalıdır", }, { ns: "Test.RGBAColorString", expected: "RGBAColorString geçerli bir RGBA rengi olmalıdır", }, { ns: "Test.HSLColorString", expected: "HSLColorString geçerli bir HSL rengi olmalıdır", }, { ns: "Test.HSLAColorString", expected: "HSLAColorString geçerli bir HSLA rengi olmalıdır", }, { ns: "Test.HexadecimalString", expected: "HexadecimalString geçerli bir onaltılık olmalıdır", }, { ns: "Test.HexColorString", expected: "HexColorString geçerli bir HEX rengi olmalıdır", }, { ns: "Test.NumberString", expected: "NumberString geçerli bir sayı olmalıdır", }, { ns: "Test.NumericString", expected: "NumericString geçerli bir sayısal değer olmalıdır", }, { ns: "Test.AlphanumString", expected: "AlphanumString yalnızca alfanümerik karakterler içerebilir", }, { ns: "Test.AlphaString", expected: "AlphaString yalnızca alfabetik karakterler içerebilir", }, { ns: "Test.LtFieldString", expected: "LtFieldString, MaxString değerinden küçük olmalıdır", }, { ns: "Test.LteFieldString", expected: "LteFieldString, MaxString değerinden küçük veya ona eşit olmalıdır", }, { ns: "Test.GtFieldString", expected: "GtFieldString, MaxString değerinden büyük olmalıdır", }, { ns: "Test.GteFieldString", expected: "GteFieldString, MaxString değerinden büyük veya ona eşit olmalıdır", }, { ns: "Test.NeFieldString", expected: "NeFieldString, EqFieldString değerine eşit olmamalıdır", }, { ns: "Test.LtCSFieldString", expected: "LtCSFieldString, Inner.LtCSFieldString değerinden küçük olmalıdır", }, { ns: "Test.LteCSFieldString", expected: "LteCSFieldString, Inner.LteCSFieldString değerinden küçük veya ona eşit olmalıdır", }, { ns: "Test.GtCSFieldString", expected: "GtCSFieldString, Inner.GtCSFieldString değerinden büyük olmalıdır", }, { ns: "Test.GteCSFieldString", expected: "GteCSFieldString, Inner.GteCSFieldString değerinden küçük veya ona eşit olmalıdır", }, { ns: "Test.NeCSFieldString", expected: "NeCSFieldString, Inner.NeCSFieldString değerine eşit olmamalıdır", }, { ns: "Test.EqCSFieldString", expected: "EqCSFieldString, Inner.EqCSFieldString değerine eşit olmalıdır", }, { ns: "Test.EqFieldString", expected: "EqFieldString, MaxString değerine eşit olmalıdır", }, { ns: "Test.GteString", expected: "GteString en az 3 karakter uzunluğunda olmalıdır", }, { ns: "Test.GteNumber", expected: "GteNumber, 5,56 veya daha büyük olmalıdır", }, { ns: "Test.GteMultiple", expected: "GteMultiple en az 2 öğe içermelidir", }, { ns: "Test.GteTime", expected: "GteTime geçerli Tarih ve Saatten büyük veya ona eşit olmalıdır", }, { ns: "Test.GtString", expected: "GtString, 3 karakter uzunluğundan fazla olmalıdır", }, { ns: "Test.GtNumber", expected: "GtNumber, 5,56 değerinden büyük olmalıdır", }, { ns: "Test.GtMultiple", expected: "GtMultiple, 2 öğeden daha fazla içermelidir", }, { ns: "Test.GtTime", expected: "GtTime geçerli Tarih ve Saatten büyük olmalıdır", }, { ns: "Test.LteString", expected: "LteString en fazla 3 karakter uzunluğunda olmalıdır", }, { ns: "Test.LteNumber", expected: "LteNumber, 5,56 veya daha az olmalıdır", }, { ns: "Test.LteMultiple", expected: "LteMultiple, maksimum 2 öğe içermelidir", }, { ns: "Test.LteTime", expected: "LteTime geçerli Tarih ve Saate eşit veya daha küçük olmalıdır", }, { ns: "Test.LtString", expected: "LtString, 3 karakter uzunluğundan daha az olmalıdır", }, { ns: "Test.LtNumber", expected: "LtNumber, 5,56 değerinden küçük olmalıdır", }, { ns: "Test.LtMultiple", expected: "LtMultiple, 2 öğeden daha az içermelidir", }, { ns: "Test.LtTime", expected: "LtTime geçerli Tarih ve Saatten daha az olmalıdır", }, { ns: "Test.NeString", expected: "NeString, değerine eşit olmamalıdır", }, { ns: "Test.NeNumber", expected: "NeNumber, 0.00 değerine eşit olmamalıdır", }, { ns: "Test.NeMultiple", expected: "NeMultiple, 0 değerine eşit olmamalıdır", }, { ns: "Test.EqString", expected: "EqString, 3 değerine eşit değil", }, { ns: "Test.EqNumber", expected: "EqNumber, 2.33 değerine eşit değil", }, { ns: "Test.EqMultiple", expected: "EqMultiple, 7 değerine eşit değil", }, { ns: "Test.MaxString", expected: "MaxString uzunluğu en fazla 3 karakter olmalıdır", }, { ns: "Test.MaxNumber", expected: "MaxNumber, 1.113,00 veya daha az olmalıdır", }, { ns: "Test.MaxMultiple", expected: "MaxMultiple maksimum 7 öğe içermelidir", }, { ns: "Test.MinString", expected: "MinString en az 1 karakter uzunluğunda olmalıdır", }, { ns: "Test.MinNumber", expected: "MinNumber, 1.113,00 veya daha büyük olmalıdır", }, { ns: "Test.MinMultiple", expected: "MinMultiple en az 7 öğe içermelidir", }, { ns: "Test.LenString", expected: "LenString uzunluğu 1 karakter olmalıdır", }, { ns: "Test.LenNumber", expected: "LenNumber, 1.113,00 değerine eşit olmalıdır", }, { ns: "Test.LenMultiple", expected: "LenMultiple, 7 öğe içermelidir", }, { ns: "Test.RequiredString", expected: "RequiredString zorunlu bir alandır", }, { ns: "Test.RequiredNumber", expected: "RequiredNumber zorunlu bir alandır", }, { ns: "Test.RequiredMultiple", expected: "RequiredMultiple zorunlu bir alandır", }, { ns: "Test.StrPtrMinLen", expected: "StrPtrMinLen en az 10 karakter uzunluğunda olmalıdır", }, { ns: "Test.StrPtrMaxLen", expected: "StrPtrMaxLen uzunluğu en fazla 1 karakter olmalıdır", }, { ns: "Test.StrPtrLen", expected: "StrPtrLen uzunluğu 2 karakter olmalıdır", }, { ns: "Test.StrPtrLt", expected: "StrPtrLt, 1 karakter uzunluğundan daha az olmalıdır", }, { ns: "Test.StrPtrLte", expected: "StrPtrLte en fazla 1 karakter uzunluğunda olmalıdır", }, { ns: "Test.StrPtrGt", expected: "StrPtrGt, 10 karakter uzunluğundan fazla olmalıdır", }, { ns: "Test.StrPtrGte", expected: "StrPtrGte en az 10 karakter uzunluğunda olmalıdır", }, { ns: "Test.OneOfString", expected: "OneOfString, [red green]'dan biri olmalıdır", }, { ns: "Test.OneOfInt", expected: "OneOfInt, [5 63]'dan biri olmalıdır", }, { ns: "Test.UniqueSlice", expected: "UniqueSlice benzersiz değerler içermelidir", }, { ns: "Test.UniqueArray", expected: "UniqueArray benzersiz değerler içermelidir", }, { ns: "Test.UniqueMap", expected: "UniqueMap benzersiz değerler içermelidir", }, } for _, tt := range tests { var fe validator.FieldError for _, e := range errs { if tt.ns == e.Namespace() { fe = e break } } NotEqual(t, fe, nil) Equal(t, tt.expected, fe.Translate(trans)) } } validator-10.4.1/translations/zh/000077500000000000000000000000001374261122600167305ustar00rootroot00000000000000validator-10.4.1/translations/zh/zh.go000066400000000000000000000764351374261122600177170ustar00rootroot00000000000000package zh import ( "fmt" "log" "reflect" "strconv" "strings" "time" "github.com/go-playground/locales" ut "github.com/go-playground/universal-translator" "github.com/go-playground/validator/v10" ) // RegisterDefaultTranslations registers a set of default translations // for all built in tag's in validator; you may add your own as desired. func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (err error) { translations := []struct { tag string translation string override bool customRegisFunc validator.RegisterTranslationsFunc customTransFunc validator.TranslationFunc }{ { tag: "required", translation: "{0}为必填字段", override: false, }, { tag: "len", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("len-string", "{0}长度必须是{1}", false); err != nil { return } //if err = ut.AddCardinal("len-string-character", "{0}字符", locales.PluralRuleOne, false); err != nil { // return //} if err = ut.AddCardinal("len-string-character", "{0}个字符", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("len-number", "{0}必须等于{1}", false); err != nil { return } if err = ut.Add("len-items", "{0}必须包含{1}", false); err != nil { return } //if err = ut.AddCardinal("len-items-item", "{0}项", locales.PluralRuleOne, false); err != nil { // return //} if err = ut.AddCardinal("len-items-item", "{0}项", locales.PluralRuleOther, false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var digits uint64 var kind reflect.Kind if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { goto END } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string c, err = ut.C("len-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("len-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string c, err = ut.C("len-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("len-items", fe.Field(), c) default: t, err = ut.T("len-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("警告: 翻译字段错误: %s", err) return fe.(error).Error() } return t }, }, { tag: "min", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("min-string", "{0}长度必须至少为{1}", false); err != nil { return } //if err = ut.AddCardinal("min-string-character", "{0}个字符", locales.PluralRuleOne, false); err != nil { // return //} if err = ut.AddCardinal("min-string-character", "{0}个字符", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("min-number", "{0}最小只能为{1}", false); err != nil { return } if err = ut.Add("min-items", "{0}必须至少包含{1}", false); err != nil { return } //if err = ut.AddCardinal("min-items-item", "{0}项", locales.PluralRuleOne, false); err != nil { // return //} if err = ut.AddCardinal("min-items-item", "{0}项", locales.PluralRuleOther, false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var digits uint64 var kind reflect.Kind if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { goto END } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string c, err = ut.C("min-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("min-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string c, err = ut.C("min-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("min-items", fe.Field(), c) default: t, err = ut.T("min-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("警告: 翻译字段错误: %s", err) return fe.(error).Error() } return t }, }, { tag: "max", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("max-string", "{0}长度不能超过{1}", false); err != nil { return } //if err = ut.AddCardinal("max-string-character", "{0}个字符", locales.PluralRuleOne, false); err != nil { // return //} if err = ut.AddCardinal("max-string-character", "{0}个字符", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("max-number", "{0}必须小于或等于{1}", false); err != nil { return } if err = ut.Add("max-items", "{0}最多只能包含{1}", false); err != nil { return } //if err = ut.AddCardinal("max-items-item", "{0}项", locales.PluralRuleOne, false); err != nil { // return //} if err = ut.AddCardinal("max-items-item", "{0}项", locales.PluralRuleOther, false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var digits uint64 var kind reflect.Kind if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { goto END } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string c, err = ut.C("max-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("max-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string c, err = ut.C("max-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("max-items", fe.Field(), c) default: t, err = ut.T("max-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("警告: 翻译字段错误: %s", err) return fe.(error).Error() } return t }, }, { tag: "eq", translation: "{0}不等于{1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { fmt.Printf("警告: 翻译字段错误: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ne", translation: "{0}不能等于{1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { fmt.Printf("警告: 翻译字段错误: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "lt", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("lt-string", "{0}长度必须小于{1}", false); err != nil { return } //if err = ut.AddCardinal("lt-string-character", "{0}个字符", locales.PluralRuleOne, false); err != nil { // return //} if err = ut.AddCardinal("lt-string-character", "{0}个字符", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lt-number", "{0}必须小于{1}", false); err != nil { return } if err = ut.Add("lt-items", "{0}必须包含少于{1}", false); err != nil { return } //if err = ut.AddCardinal("lt-items-item", "{0}项", locales.PluralRuleOne, false); err != nil { // return //} if err = ut.AddCardinal("lt-items-item", "{0}项", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lt-datetime", "{0}必须小于当前日期和时间", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("lt-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lt-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("lt-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lt-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s'不能用于struct类型.", fe.Tag()) } else { t, err = ut.T("lt-datetime", fe.Field()) } default: err = fn() if err != nil { goto END } t, err = ut.T("lt-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("警告: 翻译字段错误: %s", err) return fe.(error).Error() } return t }, }, { tag: "lte", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("lte-string", "{0}长度不能超过{1}", false); err != nil { return } //if err = ut.AddCardinal("lte-string-character", "{0} character", locales.PluralRuleOne, false); err != nil { // return //} if err = ut.AddCardinal("lte-string-character", "{0}个字符", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lte-number", "{0}必须小于或等于{1}", false); err != nil { return } if err = ut.Add("lte-items", "{0}最多只能包含{1}", false); err != nil { return } //if err = ut.AddCardinal("lte-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { // return //} if err = ut.AddCardinal("lte-items-item", "{0}项", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lte-datetime", "{0}必须小于或等于当前日期和时间", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("lte-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lte-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("lte-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lte-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s'不能用于struct类型.", fe.Tag()) } else { t, err = ut.T("lte-datetime", fe.Field()) } default: err = fn() if err != nil { goto END } t, err = ut.T("lte-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("警告: 翻译字段错误: %s", err) return fe.(error).Error() } return t }, }, { tag: "gt", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("gt-string", "{0}长度必须大于{1}", false); err != nil { return } //if err = ut.AddCardinal("gt-string-character", "{0}个字符", locales.PluralRuleOne, false); err != nil { // return //} if err = ut.AddCardinal("gt-string-character", "{0}个字符", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gt-number", "{0}必须大于{1}", false); err != nil { return } if err = ut.Add("gt-items", "{0}必须大于{1}", false); err != nil { return } //if err = ut.AddCardinal("gt-items-item", "{0}项", locales.PluralRuleOne, false); err != nil { // return //} if err = ut.AddCardinal("gt-items-item", "{0}项", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gt-datetime", "{0}必须大于当前日期和时间", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("gt-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gt-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("gt-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gt-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s'不能用于struct类型.", fe.Tag()) } else { t, err = ut.T("gt-datetime", fe.Field()) } default: err = fn() if err != nil { goto END } t, err = ut.T("gt-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("警告: 翻译字段错误: %s", err) return fe.(error).Error() } return t }, }, { tag: "gte", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("gte-string", "{0}长度必须至少为{1}", false); err != nil { return } //if err = ut.AddCardinal("gte-string-character", "{0}个字符", locales.PluralRuleOne, false); err != nil { // return //} if err = ut.AddCardinal("gte-string-character", "{0}个字符", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gte-number", "{0}必须大于或等于{1}", false); err != nil { return } if err = ut.Add("gte-items", "{0}必须至少包含{1}", false); err != nil { return } //if err = ut.AddCardinal("gte-items-item", "{0}项", locales.PluralRuleOne, false); err != nil { // return //} if err = ut.AddCardinal("gte-items-item", "{0}项", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gte-datetime", "{0}必须大于或等于当前日期和时间", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("gte-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gte-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("gte-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gte-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s'不能用于struct类型.", fe.Tag()) } else { t, err = ut.T("gte-datetime", fe.Field()) } default: err = fn() if err != nil { goto END } t, err = ut.T("gte-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("警告: 翻译字段错误: %s", err) return fe.(error).Error() } return t }, }, { tag: "eqfield", translation: "{0}必须等于{1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("警告: 翻译字段错误: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "eqcsfield", translation: "{0}必须等于{1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("警告: 翻译字段错误: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "necsfield", translation: "{0}不能等于{1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("警告: 翻译字段错误: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtcsfield", translation: "{0}必须大于{1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("警告: 翻译字段错误: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtecsfield", translation: "{0}必须大于或等于{1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("警告: 翻译字段错误: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltcsfield", translation: "{0}必须小于{1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("警告: 翻译字段错误: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltecsfield", translation: "{0}必须小于或等于{1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("警告: 翻译字段错误: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "nefield", translation: "{0}不能等于{1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("警告: 翻译字段错误: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtfield", translation: "{0}必须大于{1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("警告: 翻译字段错误: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtefield", translation: "{0}必须大于或等于{1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("警告: 翻译字段错误: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltfield", translation: "{0}必须小于{1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("警告: 翻译字段错误: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltefield", translation: "{0}必须小于或等于{1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("警告: 翻译字段错误: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "alpha", translation: "{0}只能包含字母", override: false, }, { tag: "alphanum", translation: "{0}只能包含字母和数字", override: false, }, { tag: "numeric", translation: "{0}必须是一个有效的数值", override: false, }, { tag: "number", translation: "{0}必须是一个有效的数字", override: false, }, { tag: "hexadecimal", translation: "{0}必须是一个有效的十六进制", override: false, }, { tag: "hexcolor", translation: "{0}必须是一个有效的十六进制颜色", override: false, }, { tag: "rgb", translation: "{0}必须是一个有效的RGB颜色", override: false, }, { tag: "rgba", translation: "{0}必须是一个有效的RGBA颜色", override: false, }, { tag: "hsl", translation: "{0}必须是一个有效的HSL颜色", override: false, }, { tag: "hsla", translation: "{0}必须是一个有效的HSLA颜色", override: false, }, { tag: "email", translation: "{0}必须是一个有效的邮箱", override: false, }, { tag: "url", translation: "{0}必须是一个有效的URL", override: false, }, { tag: "uri", translation: "{0}必须是一个有效的URI", override: false, }, { tag: "base64", translation: "{0}必须是一个有效的Base64字符串", override: false, }, { tag: "contains", translation: "{0}必须包含文本'{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("警告: 翻译字段错误: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "containsany", translation: "{0}必须包含至少一个以下字符'{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("警告: 翻译字段错误: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "excludes", translation: "{0}不能包含文本'{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("警告: 翻译字段错误: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "excludesall", translation: "{0}不能包含以下任何字符'{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("警告: 翻译字段错误: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "excludesrune", translation: "{0}不能包含'{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("警告: 翻译字段错误: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "isbn", translation: "{0}必须是一个有效的ISBN编号", override: false, }, { tag: "isbn10", translation: "{0}必须是一个有效的ISBN-10编号", override: false, }, { tag: "isbn13", translation: "{0}必须是一个有效的ISBN-13编号", override: false, }, { tag: "uuid", translation: "{0}必须是一个有效的UUID", override: false, }, { tag: "uuid3", translation: "{0}必须是一个有效的V3 UUID", override: false, }, { tag: "uuid4", translation: "{0}必须是一个有效的V4 UUID", override: false, }, { tag: "uuid5", translation: "{0}必须是一个有效的V5 UUID", override: false, }, { tag: "ascii", translation: "{0}必须只包含ascii字符", override: false, }, { tag: "printascii", translation: "{0}必须只包含可打印的ascii字符", override: false, }, { tag: "multibyte", translation: "{0}必须包含多字节字符", override: false, }, { tag: "datauri", translation: "{0}必须包含有效的数据URI", override: false, }, { tag: "latitude", translation: "{0}必须包含有效的纬度坐标", override: false, }, { tag: "longitude", translation: "{0}必须包含有效的经度坐标", override: false, }, { tag: "ssn", translation: "{0}必须是一个有效的社会安全号码(SSN)", override: false, }, { tag: "ipv4", translation: "{0}必须是一个有效的IPv4地址", override: false, }, { tag: "ipv6", translation: "{0}必须是一个有效的IPv6地址", override: false, }, { tag: "ip", translation: "{0}必须是一个有效的IP地址", override: false, }, { tag: "cidr", translation: "{0}必须是一个有效的无类别域间路由(CIDR)", override: false, }, { tag: "cidrv4", translation: "{0}必须是一个包含IPv4地址的有效无类别域间路由(CIDR)", override: false, }, { tag: "cidrv6", translation: "{0}必须是一个包含IPv6地址的有效无类别域间路由(CIDR)", override: false, }, { tag: "tcp_addr", translation: "{0}必须是一个有效的TCP地址", override: false, }, { tag: "tcp4_addr", translation: "{0}必须是一个有效的IPv4 TCP地址", override: false, }, { tag: "tcp6_addr", translation: "{0}必须是一个有效的IPv6 TCP地址", override: false, }, { tag: "udp_addr", translation: "{0}必须是一个有效的UDP地址", override: false, }, { tag: "udp4_addr", translation: "{0}必须是一个有效的IPv4 UDP地址", override: false, }, { tag: "udp6_addr", translation: "{0}必须是一个有效的IPv6 UDP地址", override: false, }, { tag: "ip_addr", translation: "{0}必须是一个有效的IP地址", override: false, }, { tag: "ip4_addr", translation: "{0}必须是一个有效的IPv4地址", override: false, }, { tag: "ip6_addr", translation: "{0}必须是一个有效的IPv6地址", override: false, }, { tag: "unix_addr", translation: "{0}必须是一个有效的UNIX地址", override: false, }, { tag: "mac", translation: "{0}必须是一个有效的MAC地址", override: false, }, { tag: "iscolor", translation: "{0}必须是一个有效的颜色", override: false, }, { tag: "oneof", translation: "{0}必须是[{1}]中的一个", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { s, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("警告: 翻译字段错误: %#v", fe) return fe.(error).Error() } return s }, }, { tag: "json", translation: "{0}必须是一个JSON字符串", override: false, }, { tag: "lowercase", translation: "{0}必须是小写字母", override: false, }, { tag: "uppercase", translation: "{0}必须是大写字母", override: false, }, { tag: "datetime", translation: "{0}的格式必须是{1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("警告: 翻译字段错误: %#v", fe) return fe.(error).Error() } return t }, }, } for _, t := range translations { if t.customTransFunc != nil && t.customRegisFunc != nil { err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, t.customTransFunc) } else if t.customTransFunc != nil && t.customRegisFunc == nil { err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), t.customTransFunc) } else if t.customTransFunc == nil && t.customRegisFunc != nil { err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, translateFunc) } else { err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), translateFunc) } if err != nil { return } } return } func registrationFunc(tag string, translation string, override bool) validator.RegisterTranslationsFunc { return func(ut ut.Translator) (err error) { if err = ut.Add(tag, translation, override); err != nil { return } return } } func translateFunc(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field()) if err != nil { log.Printf("警告: 翻译字段错误: %#v", fe) return fe.(error).Error() } return t } validator-10.4.1/translations/zh/zh_test.go000066400000000000000000000442321374261122600207440ustar00rootroot00000000000000package zh import ( "testing" "time" . "github.com/go-playground/assert/v2" zhongwen "github.com/go-playground/locales/zh" ut "github.com/go-playground/universal-translator" "github.com/go-playground/validator/v10" ) func TestTranslations(t *testing.T) { zh := zhongwen.New() uni := ut.New(zh, zh) trans, _ := uni.GetTranslator("zh") validate := validator.New() err := RegisterDefaultTranslations(validate, trans) Equal(t, err, nil) type Inner struct { EqCSFieldString string NeCSFieldString string GtCSFieldString string GteCSFieldString string LtCSFieldString string LteCSFieldString string } type Test struct { Inner Inner RequiredString string `validate:"required"` RequiredNumber int `validate:"required"` RequiredMultiple []string `validate:"required"` LenString string `validate:"len=1"` LenNumber float64 `validate:"len=1113.00"` LenMultiple []string `validate:"len=7"` MinString string `validate:"min=1"` MinNumber float64 `validate:"min=1113.00"` MinMultiple []string `validate:"min=7"` MaxString string `validate:"max=3"` MaxNumber float64 `validate:"max=1113.00"` MaxMultiple []string `validate:"max=7"` EqString string `validate:"eq=3"` EqNumber float64 `validate:"eq=2.33"` EqMultiple []string `validate:"eq=7"` NeString string `validate:"ne="` NeNumber float64 `validate:"ne=0.00"` NeMultiple []string `validate:"ne=0"` LtString string `validate:"lt=3"` LtNumber float64 `validate:"lt=5.56"` LtMultiple []string `validate:"lt=2"` LtTime time.Time `validate:"lt"` LteString string `validate:"lte=3"` LteNumber float64 `validate:"lte=5.56"` LteMultiple []string `validate:"lte=2"` LteTime time.Time `validate:"lte"` GtString string `validate:"gt=3"` GtNumber float64 `validate:"gt=5.56"` GtMultiple []string `validate:"gt=2"` GtTime time.Time `validate:"gt"` GteString string `validate:"gte=3"` GteNumber float64 `validate:"gte=5.56"` GteMultiple []string `validate:"gte=2"` GteTime time.Time `validate:"gte"` EqFieldString string `validate:"eqfield=MaxString"` EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"` NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"` GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"` GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"` LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"` LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"` NeFieldString string `validate:"nefield=EqFieldString"` GtFieldString string `validate:"gtfield=MaxString"` GteFieldString string `validate:"gtefield=MaxString"` LtFieldString string `validate:"ltfield=MaxString"` LteFieldString string `validate:"ltefield=MaxString"` AlphaString string `validate:"alpha"` AlphanumString string `validate:"alphanum"` NumericString string `validate:"numeric"` NumberString string `validate:"number"` HexadecimalString string `validate:"hexadecimal"` HexColorString string `validate:"hexcolor"` RGBColorString string `validate:"rgb"` RGBAColorString string `validate:"rgba"` HSLColorString string `validate:"hsl"` HSLAColorString string `validate:"hsla"` Email string `validate:"email"` URL string `validate:"url"` URI string `validate:"uri"` Base64 string `validate:"base64"` Contains string `validate:"contains=purpose"` ContainsAny string `validate:"containsany=!@#$"` Excludes string `validate:"excludes=text"` ExcludesAll string `validate:"excludesall=!@#$"` ExcludesRune string `validate:"excludesrune=☻"` ISBN string `validate:"isbn"` ISBN10 string `validate:"isbn10"` ISBN13 string `validate:"isbn13"` UUID string `validate:"uuid"` UUID3 string `validate:"uuid3"` UUID4 string `validate:"uuid4"` UUID5 string `validate:"uuid5"` ASCII string `validate:"ascii"` PrintableASCII string `validate:"printascii"` MultiByte string `validate:"multibyte"` DataURI string `validate:"datauri"` Latitude string `validate:"latitude"` Longitude string `validate:"longitude"` SSN string `validate:"ssn"` IP string `validate:"ip"` IPv4 string `validate:"ipv4"` IPv6 string `validate:"ipv6"` CIDR string `validate:"cidr"` CIDRv4 string `validate:"cidrv4"` CIDRv6 string `validate:"cidrv6"` TCPAddr string `validate:"tcp_addr"` TCPAddrv4 string `validate:"tcp4_addr"` TCPAddrv6 string `validate:"tcp6_addr"` UDPAddr string `validate:"udp_addr"` UDPAddrv4 string `validate:"udp4_addr"` UDPAddrv6 string `validate:"udp6_addr"` IPAddr string `validate:"ip_addr"` IPAddrv4 string `validate:"ip4_addr"` IPAddrv6 string `validate:"ip6_addr"` UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future MAC string `validate:"mac"` IsColor string `validate:"iscolor"` StrPtrMinLen *string `validate:"min=10"` StrPtrMaxLen *string `validate:"max=1"` StrPtrLen *string `validate:"len=2"` StrPtrLt *string `validate:"lt=1"` StrPtrLte *string `validate:"lte=1"` StrPtrGt *string `validate:"gt=10"` StrPtrGte *string `validate:"gte=10"` OneOfString string `validate:"oneof=red green"` OneOfInt int `validate:"oneof=5 63"` JsonString string `validate:"json"` LowercaseString string `validate:"lowercase"` UppercaseString string `validate:"uppercase"` Datetime string `validate:"datetime=2006-01-02"` } var test Test test.Inner.EqCSFieldString = "1234" test.Inner.GtCSFieldString = "1234" test.Inner.GteCSFieldString = "1234" test.MaxString = "1234" test.MaxNumber = 2000 test.MaxMultiple = make([]string, 9) test.LtString = "1234" test.LtNumber = 6 test.LtMultiple = make([]string, 3) test.LtTime = time.Now().Add(time.Hour * 24) test.LteString = "1234" test.LteNumber = 6 test.LteMultiple = make([]string, 3) test.LteTime = time.Now().Add(time.Hour * 24) test.LtFieldString = "12345" test.LteFieldString = "12345" test.LtCSFieldString = "1234" test.LteCSFieldString = "1234" test.AlphaString = "abc3" test.AlphanumString = "abc3!" test.NumericString = "12E.00" test.NumberString = "12E" test.Excludes = "this is some test text" test.ExcludesAll = "This is Great!" test.ExcludesRune = "Love it ☻" test.ASCII = "カタカナ" test.PrintableASCII = "カタカナ" test.MultiByte = "1234feerf" s := "toolong" test.StrPtrMaxLen = &s test.StrPtrLen = &s test.JsonString = "{\"foo\":\"bar\",}" test.LowercaseString = "ABCDEFG" test.UppercaseString = "abcdefg" test.Datetime = "20060102" err = validate.Struct(test) NotEqual(t, err, nil) errs, ok := err.(validator.ValidationErrors) Equal(t, ok, true) tests := []struct { ns string expected string }{ { ns: "Test.IsColor", expected: "IsColor必须是一个有效的颜色", }, { ns: "Test.MAC", expected: "MAC必须是一个有效的MAC地址", }, { ns: "Test.IPAddr", expected: "IPAddr必须是一个有效的IP地址", }, { ns: "Test.IPAddrv4", expected: "IPAddrv4必须是一个有效的IPv4地址", }, { ns: "Test.IPAddrv6", expected: "IPAddrv6必须是一个有效的IPv6地址", }, { ns: "Test.UDPAddr", expected: "UDPAddr必须是一个有效的UDP地址", }, { ns: "Test.UDPAddrv4", expected: "UDPAddrv4必须是一个有效的IPv4 UDP地址", }, { ns: "Test.UDPAddrv6", expected: "UDPAddrv6必须是一个有效的IPv6 UDP地址", }, { ns: "Test.TCPAddr", expected: "TCPAddr必须是一个有效的TCP地址", }, { ns: "Test.TCPAddrv4", expected: "TCPAddrv4必须是一个有效的IPv4 TCP地址", }, { ns: "Test.TCPAddrv6", expected: "TCPAddrv6必须是一个有效的IPv6 TCP地址", }, { ns: "Test.CIDR", expected: "CIDR必须是一个有效的无类别域间路由(CIDR)", }, { ns: "Test.CIDRv4", expected: "CIDRv4必须是一个包含IPv4地址的有效无类别域间路由(CIDR)", }, { ns: "Test.CIDRv6", expected: "CIDRv6必须是一个包含IPv6地址的有效无类别域间路由(CIDR)", }, { ns: "Test.SSN", expected: "SSN必须是一个有效的社会安全号码(SSN)", }, { ns: "Test.IP", expected: "IP必须是一个有效的IP地址", }, { ns: "Test.IPv4", expected: "IPv4必须是一个有效的IPv4地址", }, { ns: "Test.IPv6", expected: "IPv6必须是一个有效的IPv6地址", }, { ns: "Test.DataURI", expected: "DataURI必须包含有效的数据URI", }, { ns: "Test.Latitude", expected: "Latitude必须包含有效的纬度坐标", }, { ns: "Test.Longitude", expected: "Longitude必须包含有效的经度坐标", }, { ns: "Test.MultiByte", expected: "MultiByte必须包含多字节字符", }, { ns: "Test.ASCII", expected: "ASCII必须只包含ascii字符", }, { ns: "Test.PrintableASCII", expected: "PrintableASCII必须只包含可打印的ascii字符", }, { ns: "Test.UUID", expected: "UUID必须是一个有效的UUID", }, { ns: "Test.UUID3", expected: "UUID3必须是一个有效的V3 UUID", }, { ns: "Test.UUID4", expected: "UUID4必须是一个有效的V4 UUID", }, { ns: "Test.UUID5", expected: "UUID5必须是一个有效的V5 UUID", }, { ns: "Test.ISBN", expected: "ISBN必须是一个有效的ISBN编号", }, { ns: "Test.ISBN10", expected: "ISBN10必须是一个有效的ISBN-10编号", }, { ns: "Test.ISBN13", expected: "ISBN13必须是一个有效的ISBN-13编号", }, { ns: "Test.Excludes", expected: "Excludes不能包含文本'text'", }, { ns: "Test.ExcludesAll", expected: "ExcludesAll不能包含以下任何字符'!@#$'", }, { ns: "Test.ExcludesRune", expected: "ExcludesRune不能包含'☻'", }, { ns: "Test.ContainsAny", expected: "ContainsAny必须包含至少一个以下字符'!@#$'", }, { ns: "Test.Contains", expected: "Contains必须包含文本'purpose'", }, { ns: "Test.Base64", expected: "Base64必须是一个有效的Base64字符串", }, { ns: "Test.Email", expected: "Email必须是一个有效的邮箱", }, { ns: "Test.URL", expected: "URL必须是一个有效的URL", }, { ns: "Test.URI", expected: "URI必须是一个有效的URI", }, { ns: "Test.RGBColorString", expected: "RGBColorString必须是一个有效的RGB颜色", }, { ns: "Test.RGBAColorString", expected: "RGBAColorString必须是一个有效的RGBA颜色", }, { ns: "Test.HSLColorString", expected: "HSLColorString必须是一个有效的HSL颜色", }, { ns: "Test.HSLAColorString", expected: "HSLAColorString必须是一个有效的HSLA颜色", }, { ns: "Test.HexadecimalString", expected: "HexadecimalString必须是一个有效的十六进制", }, { ns: "Test.HexColorString", expected: "HexColorString必须是一个有效的十六进制颜色", }, { ns: "Test.NumberString", expected: "NumberString必须是一个有效的数字", }, { ns: "Test.NumericString", expected: "NumericString必须是一个有效的数值", }, { ns: "Test.AlphanumString", expected: "AlphanumString只能包含字母和数字", }, { ns: "Test.AlphaString", expected: "AlphaString只能包含字母", }, { ns: "Test.LtFieldString", expected: "LtFieldString必须小于MaxString", }, { ns: "Test.LteFieldString", expected: "LteFieldString必须小于或等于MaxString", }, { ns: "Test.GtFieldString", expected: "GtFieldString必须大于MaxString", }, { ns: "Test.GteFieldString", expected: "GteFieldString必须大于或等于MaxString", }, { ns: "Test.NeFieldString", expected: "NeFieldString不能等于EqFieldString", }, { ns: "Test.LtCSFieldString", expected: "LtCSFieldString必须小于Inner.LtCSFieldString", }, { ns: "Test.LteCSFieldString", expected: "LteCSFieldString必须小于或等于Inner.LteCSFieldString", }, { ns: "Test.GtCSFieldString", expected: "GtCSFieldString必须大于Inner.GtCSFieldString", }, { ns: "Test.GteCSFieldString", expected: "GteCSFieldString必须大于或等于Inner.GteCSFieldString", }, { ns: "Test.NeCSFieldString", expected: "NeCSFieldString不能等于Inner.NeCSFieldString", }, { ns: "Test.EqCSFieldString", expected: "EqCSFieldString必须等于Inner.EqCSFieldString", }, { ns: "Test.EqFieldString", expected: "EqFieldString必须等于MaxString", }, { ns: "Test.GteString", expected: "GteString长度必须至少为3个字符", }, { ns: "Test.GteNumber", expected: "GteNumber必须大于或等于5.56", }, { ns: "Test.GteMultiple", expected: "GteMultiple必须至少包含2项", }, { ns: "Test.GteTime", expected: "GteTime必须大于或等于当前日期和时间", }, { ns: "Test.GtString", expected: "GtString长度必须大于3个字符", }, { ns: "Test.GtNumber", expected: "GtNumber必须大于5.56", }, { ns: "Test.GtMultiple", expected: "GtMultiple必须大于2项", }, { ns: "Test.GtTime", expected: "GtTime必须大于当前日期和时间", }, { ns: "Test.LteString", expected: "LteString长度不能超过3个字符", }, { ns: "Test.LteNumber", expected: "LteNumber必须小于或等于5.56", }, { ns: "Test.LteMultiple", expected: "LteMultiple最多只能包含2项", }, { ns: "Test.LteTime", expected: "LteTime必须小于或等于当前日期和时间", }, { ns: "Test.LtString", expected: "LtString长度必须小于3个字符", }, { ns: "Test.LtNumber", expected: "LtNumber必须小于5.56", }, { ns: "Test.LtMultiple", expected: "LtMultiple必须包含少于2项", }, { ns: "Test.LtTime", expected: "LtTime必须小于当前日期和时间", }, { ns: "Test.NeString", expected: "NeString不能等于", }, { ns: "Test.NeNumber", expected: "NeNumber不能等于0.00", }, { ns: "Test.NeMultiple", expected: "NeMultiple不能等于0", }, { ns: "Test.EqString", expected: "EqString不等于3", }, { ns: "Test.EqNumber", expected: "EqNumber不等于2.33", }, { ns: "Test.EqMultiple", expected: "EqMultiple不等于7", }, { ns: "Test.MaxString", expected: "MaxString长度不能超过3个字符", }, { ns: "Test.MaxNumber", expected: "MaxNumber必须小于或等于1,113.00", }, { ns: "Test.MaxMultiple", expected: "MaxMultiple最多只能包含7项", }, { ns: "Test.MinString", expected: "MinString长度必须至少为1个字符", }, { ns: "Test.MinNumber", expected: "MinNumber最小只能为1,113.00", }, { ns: "Test.MinMultiple", expected: "MinMultiple必须至少包含7项", }, { ns: "Test.LenString", expected: "LenString长度必须是1个字符", }, { ns: "Test.LenNumber", expected: "LenNumber必须等于1,113.00", }, { ns: "Test.LenMultiple", expected: "LenMultiple必须包含7项", }, { ns: "Test.RequiredString", expected: "RequiredString为必填字段", }, { ns: "Test.RequiredNumber", expected: "RequiredNumber为必填字段", }, { ns: "Test.RequiredMultiple", expected: "RequiredMultiple为必填字段", }, { ns: "Test.StrPtrMinLen", expected: "StrPtrMinLen长度必须至少为10个字符", }, { ns: "Test.StrPtrMaxLen", expected: "StrPtrMaxLen长度不能超过1个字符", }, { ns: "Test.StrPtrLen", expected: "StrPtrLen长度必须是2个字符", }, { ns: "Test.StrPtrLt", expected: "StrPtrLt长度必须小于1个字符", }, { ns: "Test.StrPtrLte", expected: "StrPtrLte长度不能超过1个字符", }, { ns: "Test.StrPtrGt", expected: "StrPtrGt长度必须大于10个字符", }, { ns: "Test.StrPtrGte", expected: "StrPtrGte长度必须至少为10个字符", }, { ns: "Test.OneOfString", expected: "OneOfString必须是[red green]中的一个", }, { ns: "Test.OneOfInt", expected: "OneOfInt必须是[5 63]中的一个", }, { ns: "Test.JsonString", expected: "JsonString必须是一个JSON字符串", }, { ns: "Test.LowercaseString", expected: "LowercaseString必须是小写字母", }, { ns: "Test.UppercaseString", expected: "UppercaseString必须是大写字母", }, { ns: "Test.Datetime", expected: "Datetime的格式必须是2006-01-02", }, } for _, tt := range tests { var fe validator.FieldError for _, e := range errs { if tt.ns == e.Namespace() { fe = e break } } NotEqual(t, fe, nil) Equal(t, tt.expected, fe.Translate(trans)) } } validator-10.4.1/translations/zh_tw/000077500000000000000000000000001374261122600174425ustar00rootroot00000000000000validator-10.4.1/translations/zh_tw/zh_tw.go000066400000000000000000000757341374261122600211440ustar00rootroot00000000000000package zh_tw import ( "fmt" "log" "reflect" "strconv" "strings" "time" "github.com/go-playground/locales" ut "github.com/go-playground/universal-translator" "github.com/go-playground/validator/v10" ) // RegisterDefaultTranslations registers a set of default translations // for all built in tag's in validator; you may add your own as desired. func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (err error) { translations := []struct { tag string translation string override bool customRegisFunc validator.RegisterTranslationsFunc customTransFunc validator.TranslationFunc }{ { tag: "required", translation: "{0}為必填欄位", override: false, }, { tag: "len", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("len-string", "{0}長度必須為{1}", false); err != nil { return } //if err = ut.AddCardinal("len-string-character", "{0}字元", locales.PluralRuleOne, false); err != nil { // return //} if err = ut.AddCardinal("len-string-character", "{0}個字元", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("len-number", "{0}必須等於{1}", false); err != nil { return } if err = ut.Add("len-items", "{0}必須包含{1}", false); err != nil { return } //if err = ut.AddCardinal("len-items-item", "{0}項", locales.PluralRuleOne, false); err != nil { // return //} if err = ut.AddCardinal("len-items-item", "{0}項", locales.PluralRuleOther, false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var digits uint64 var kind reflect.Kind if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { goto END } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string c, err = ut.C("len-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("len-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string c, err = ut.C("len-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("len-items", fe.Field(), c) default: t, err = ut.T("len-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("警告: 翻譯欄位錯誤: %s", err) return fe.(error).Error() } return t }, }, { tag: "min", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("min-string", "{0}長度必須至少為{1}", false); err != nil { return } //if err = ut.AddCardinal("min-string-character", "{0}個字元", locales.PluralRuleOne, false); err != nil { // return //} if err = ut.AddCardinal("min-string-character", "{0}個字元", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("min-number", "{0}最小只能為{1}", false); err != nil { return } if err = ut.Add("min-items", "{0}必須至少包含{1}", false); err != nil { return } //if err = ut.AddCardinal("min-items-item", "{0}項", locales.PluralRuleOne, false); err != nil { // return //} if err = ut.AddCardinal("min-items-item", "{0}項", locales.PluralRuleOther, false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var digits uint64 var kind reflect.Kind if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { goto END } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string c, err = ut.C("min-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("min-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string c, err = ut.C("min-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("min-items", fe.Field(), c) default: t, err = ut.T("min-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("警告: 翻譯欄位錯誤: %s", err) return fe.(error).Error() } return t }, }, { tag: "max", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("max-string", "{0}長度不能超過{1}", false); err != nil { return } //if err = ut.AddCardinal("max-string-character", "{0}個字元", locales.PluralRuleOne, false); err != nil { // return //} if err = ut.AddCardinal("max-string-character", "{0}個字元", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("max-number", "{0}必須小於或等於{1}", false); err != nil { return } if err = ut.Add("max-items", "{0}最多只能包含{1}", false); err != nil { return } //if err = ut.AddCardinal("max-items-item", "{0}項", locales.PluralRuleOne, false); err != nil { // return //} if err = ut.AddCardinal("max-items-item", "{0}項", locales.PluralRuleOther, false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var digits uint64 var kind reflect.Kind if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { goto END } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string c, err = ut.C("max-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("max-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string c, err = ut.C("max-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("max-items", fe.Field(), c) default: t, err = ut.T("max-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("警告: 翻譯欄位錯誤: %s", err) return fe.(error).Error() } return t }, }, { tag: "eq", translation: "{0}不等於{1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { fmt.Printf("警告: 翻譯欄位錯誤: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ne", translation: "{0}不能等於{1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { fmt.Printf("警告: 翻譯欄位錯誤: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "lt", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("lt-string", "{0}長度必須小於{1}", false); err != nil { return } //if err = ut.AddCardinal("lt-string-character", "{0}個字元", locales.PluralRuleOne, false); err != nil { // return //} if err = ut.AddCardinal("lt-string-character", "{0}個字元", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lt-number", "{0}必須小於{1}", false); err != nil { return } if err = ut.Add("lt-items", "{0}必須包含少於{1}", false); err != nil { return } //if err = ut.AddCardinal("lt-items-item", "{0}項", locales.PluralRuleOne, false); err != nil { // return //} if err = ut.AddCardinal("lt-items-item", "{0}項", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lt-datetime", "{0}必須小於目前日期和時間", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("lt-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lt-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("lt-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lt-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s'不能用於struct類型.", fe.Tag()) } else { t, err = ut.T("lt-datetime", fe.Field()) } default: err = fn() if err != nil { goto END } t, err = ut.T("lt-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("警告: 翻譯欄位錯誤: %s", err) return fe.(error).Error() } return t }, }, { tag: "lte", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("lte-string", "{0}長度不能超過{1}", false); err != nil { return } //if err = ut.AddCardinal("lte-string-character", "{0} character", locales.PluralRuleOne, false); err != nil { // return //} if err = ut.AddCardinal("lte-string-character", "{0}個字元", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lte-number", "{0}必須小於或等於{1}", false); err != nil { return } if err = ut.Add("lte-items", "{0}最多只能包含{1}", false); err != nil { return } //if err = ut.AddCardinal("lte-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { // return //} if err = ut.AddCardinal("lte-items-item", "{0}項", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("lte-datetime", "{0}必須小於或等於目前日期和時間", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("lte-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lte-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("lte-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("lte-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s'不能用於struct類型.", fe.Tag()) } else { t, err = ut.T("lte-datetime", fe.Field()) } default: err = fn() if err != nil { goto END } t, err = ut.T("lte-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("警告: 翻譯欄位錯誤: %s", err) return fe.(error).Error() } return t }, }, { tag: "gt", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("gt-string", "{0}長度必須大於{1}", false); err != nil { return } //if err = ut.AddCardinal("gt-string-character", "{0}個字元", locales.PluralRuleOne, false); err != nil { // return //} if err = ut.AddCardinal("gt-string-character", "{0}個字元", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gt-number", "{0}必須大於{1}", false); err != nil { return } if err = ut.Add("gt-items", "{0}必須大於{1}", false); err != nil { return } //if err = ut.AddCardinal("gt-items-item", "{0}項", locales.PluralRuleOne, false); err != nil { // return //} if err = ut.AddCardinal("gt-items-item", "{0}項", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gt-datetime", "{0}必須大於目前日期和時間", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("gt-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gt-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("gt-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gt-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s'不能用於struct類型.", fe.Tag()) } else { t, err = ut.T("gt-datetime", fe.Field()) } default: err = fn() if err != nil { goto END } t, err = ut.T("gt-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("警告: 翻譯欄位錯誤: %s", err) return fe.(error).Error() } return t }, }, { tag: "gte", customRegisFunc: func(ut ut.Translator) (err error) { if err = ut.Add("gte-string", "{0}長度必須至少為{1}", false); err != nil { return } //if err = ut.AddCardinal("gte-string-character", "{0}個字元", locales.PluralRuleOne, false); err != nil { // return //} if err = ut.AddCardinal("gte-string-character", "{0}個字元", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gte-number", "{0}必須大於或等於{1}", false); err != nil { return } if err = ut.Add("gte-items", "{0}必須至少包含{1}", false); err != nil { return } //if err = ut.AddCardinal("gte-items-item", "{0}項", locales.PluralRuleOne, false); err != nil { // return //} if err = ut.AddCardinal("gte-items-item", "{0}項", locales.PluralRuleOther, false); err != nil { return } if err = ut.Add("gte-datetime", "{0}必須大於或等於目前日期和時間", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 var digits uint64 var kind reflect.Kind fn := func() (err error) { if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } f64, err = strconv.ParseFloat(fe.Param(), 64) return } kind = fe.Kind() if kind == reflect.Ptr { kind = fe.Type().Elem().Kind() } switch kind { case reflect.String: var c string err = fn() if err != nil { goto END } c, err = ut.C("gte-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gte-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string err = fn() if err != nil { goto END } c, err = ut.C("gte-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } t, err = ut.T("gte-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { err = fmt.Errorf("tag '%s'不能用於struct類型.", fe.Tag()) } else { t, err = ut.T("gte-datetime", fe.Field()) } default: err = fn() if err != nil { goto END } t, err = ut.T("gte-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: if err != nil { fmt.Printf("警告: 翻譯欄位錯誤: %s", err) return fe.(error).Error() } return t }, }, { tag: "eqfield", translation: "{0}必須等於{1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("警告: 翻譯欄位錯誤: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "eqcsfield", translation: "{0}必須等於{1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("警告: 翻譯欄位錯誤: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "necsfield", translation: "{0}不能等於{1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("警告: 翻譯欄位錯誤: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtcsfield", translation: "{0}必須大於{1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("警告: 翻譯欄位錯誤: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtecsfield", translation: "{0}必須大於或等於{1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("警告: 翻譯欄位錯誤: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltcsfield", translation: "{0}必須小於{1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("警告: 翻譯欄位錯誤: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltecsfield", translation: "{0}必須小於或等於{1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("警告: 翻譯欄位錯誤: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "nefield", translation: "{0}不能等於{1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("警告: 翻譯欄位錯誤: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtfield", translation: "{0}必須大於{1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("警告: 翻譯欄位錯誤: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "gtefield", translation: "{0}必須大於或等於{1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("警告: 翻譯欄位錯誤: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltfield", translation: "{0}必須小於{1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("警告: 翻譯欄位錯誤: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "ltefield", translation: "{0}必須小於或等於{1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("警告: 翻譯欄位錯誤: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "alpha", translation: "{0}只能包含字母", override: false, }, { tag: "alphanum", translation: "{0}只能包含字母和數字", override: false, }, { tag: "numeric", translation: "{0}必須是一個有效的數值", override: false, }, { tag: "number", translation: "{0}必須是一個有效的數字", override: false, }, { tag: "hexadecimal", translation: "{0}必須是一個有效的十六進制", override: false, }, { tag: "hexcolor", translation: "{0}必須是一個有效的十六進制顏色", override: false, }, { tag: "rgb", translation: "{0}必須是一個有效的RGB顏色", override: false, }, { tag: "rgba", translation: "{0}必須是一個有效的RGBA顏色", override: false, }, { tag: "hsl", translation: "{0}必須是一個有效的HSL顏色", override: false, }, { tag: "hsla", translation: "{0}必須是一個有效的HSLA顏色", override: false, }, { tag: "email", translation: "{0}必須是一個有效的信箱", override: false, }, { tag: "url", translation: "{0}必須是一個有效的URL", override: false, }, { tag: "uri", translation: "{0}必須是一個有效的URI", override: false, }, { tag: "base64", translation: "{0}必須是一個有效的Base64字元串", override: false, }, { tag: "contains", translation: "{0}必須包含文字'{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("警告: 翻譯欄位錯誤: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "containsany", translation: "{0}必須包含至少一個以下字元'{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("警告: 翻譯欄位錯誤: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "excludes", translation: "{0}不能包含文字'{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("警告: 翻譯欄位錯誤: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "excludesall", translation: "{0}不能包含以下任何字元'{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("警告: 翻譯欄位錯誤: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "excludesrune", translation: "{0}不能包含'{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("警告: 翻譯欄位錯誤: %#v", fe) return fe.(error).Error() } return t }, }, { tag: "isbn", translation: "{0}必須是一個有效的ISBN編號", override: false, }, { tag: "isbn10", translation: "{0}必須是一個有效的ISBN-10編號", override: false, }, { tag: "isbn13", translation: "{0}必須是一個有效的ISBN-13編號", override: false, }, { tag: "uuid", translation: "{0}必須是一個有效的UUID", override: false, }, { tag: "uuid3", translation: "{0}必須是一個有效的V3 UUID", override: false, }, { tag: "uuid4", translation: "{0}必須是一個有效的V4 UUID", override: false, }, { tag: "uuid5", translation: "{0}必須是一個有效的V5 UUID", override: false, }, { tag: "ascii", translation: "{0}必須只包含ascii字元", override: false, }, { tag: "printascii", translation: "{0}必須只包含可輸出的ascii字元", override: false, }, { tag: "multibyte", translation: "{0}必須包含多個字元", override: false, }, { tag: "datauri", translation: "{0}必須包含有效的數據URI", override: false, }, { tag: "latitude", translation: "{0}必須包含有效的緯度座標", override: false, }, { tag: "longitude", translation: "{0}必須包含有效的經度座標", override: false, }, { tag: "ssn", translation: "{0}必須是一個有效的社會安全編號(SSN)", override: false, }, { tag: "ipv4", translation: "{0}必須是一個有效的IPv4地址", override: false, }, { tag: "ipv6", translation: "{0}必須是一個有效的IPv6地址", override: false, }, { tag: "ip", translation: "{0}必須是一個有效的IP地址", override: false, }, { tag: "cidr", translation: "{0}必須是一個有效的無類別域間路由(CIDR)", override: false, }, { tag: "cidrv4", translation: "{0}必須是一个包含IPv4地址的有效無類別域間路由(CIDR)", override: false, }, { tag: "cidrv6", translation: "{0}必須是一个包含IPv6地址的有效無類別域間路由(CIDR)", override: false, }, { tag: "tcp_addr", translation: "{0}必須是一個有效的TCP地址", override: false, }, { tag: "tcp4_addr", translation: "{0}必須是一個有效的IPv4 TCP地址", override: false, }, { tag: "tcp6_addr", translation: "{0}必須是一個有效的IPv6 TCP地址", override: false, }, { tag: "udp_addr", translation: "{0}必須是一個有效的UDP地址", override: false, }, { tag: "udp4_addr", translation: "{0}必須是一個有效的IPv4 UDP地址", override: false, }, { tag: "udp6_addr", translation: "{0}必須是一個有效的IPv6 UDP地址", override: false, }, { tag: "ip_addr", translation: "{0}必須是一個有效的IP地址", override: false, }, { tag: "ip4_addr", translation: "{0}必須是一個有效的IPv4地址", override: false, }, { tag: "ip6_addr", translation: "{0}必須是一個有效的IPv6地址", override: false, }, { tag: "unix_addr", translation: "{0}必須是一個有效的UNIX地址", override: false, }, { tag: "mac", translation: "{0}必須是一個有效的MAC地址", override: false, }, { tag: "iscolor", translation: "{0}必須是一個有效的顏色", override: false, }, { tag: "oneof", translation: "{0}必須是[{1}]中的一個", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { s, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("警告: 翻譯欄位錯誤: %#v", fe) return fe.(error).Error() } return s }, }, { tag: "datetime", translation: "{0}與{1}格式不匹配", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("警告: 翻譯欄位錯誤: %#v", fe) return fe.(error).Error() } return t }, }, } for _, t := range translations { if t.customTransFunc != nil && t.customRegisFunc != nil { err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, t.customTransFunc) } else if t.customTransFunc != nil && t.customRegisFunc == nil { err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), t.customTransFunc) } else if t.customTransFunc == nil && t.customRegisFunc != nil { err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, translateFunc) } else { err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), translateFunc) } if err != nil { return } } return } func registrationFunc(tag string, translation string, override bool) validator.RegisterTranslationsFunc { return func(ut ut.Translator) (err error) { if err = ut.Add(tag, translation, override); err != nil { return } return } } func translateFunc(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field()) if err != nil { log.Printf("警告: 翻譯欄位錯誤: %#v", fe) return fe.(error).Error() } return t } validator-10.4.1/translations/zh_tw/zh_tw_test.go000066400000000000000000000431671374261122600221760ustar00rootroot00000000000000package zh_tw import ( "testing" "time" . "github.com/go-playground/assert/v2" zhongwen "github.com/go-playground/locales/zh_Hant_TW" ut "github.com/go-playground/universal-translator" "github.com/go-playground/validator/v10" ) func TestTranslations(t *testing.T) { zh := zhongwen.New() uni := ut.New(zh, zh) trans, _ := uni.GetTranslator("zh") validate := validator.New() err := RegisterDefaultTranslations(validate, trans) Equal(t, err, nil) type Inner struct { EqCSFieldString string NeCSFieldString string GtCSFieldString string GteCSFieldString string LtCSFieldString string LteCSFieldString string } type Test struct { Inner Inner RequiredString string `validate:"required"` RequiredNumber int `validate:"required"` RequiredMultiple []string `validate:"required"` LenString string `validate:"len=1"` LenNumber float64 `validate:"len=1113.00"` LenMultiple []string `validate:"len=7"` MinString string `validate:"min=1"` MinNumber float64 `validate:"min=1113.00"` MinMultiple []string `validate:"min=7"` MaxString string `validate:"max=3"` MaxNumber float64 `validate:"max=1113.00"` MaxMultiple []string `validate:"max=7"` EqString string `validate:"eq=3"` EqNumber float64 `validate:"eq=2.33"` EqMultiple []string `validate:"eq=7"` NeString string `validate:"ne="` NeNumber float64 `validate:"ne=0.00"` NeMultiple []string `validate:"ne=0"` LtString string `validate:"lt=3"` LtNumber float64 `validate:"lt=5.56"` LtMultiple []string `validate:"lt=2"` LtTime time.Time `validate:"lt"` LteString string `validate:"lte=3"` LteNumber float64 `validate:"lte=5.56"` LteMultiple []string `validate:"lte=2"` LteTime time.Time `validate:"lte"` GtString string `validate:"gt=3"` GtNumber float64 `validate:"gt=5.56"` GtMultiple []string `validate:"gt=2"` GtTime time.Time `validate:"gt"` GteString string `validate:"gte=3"` GteNumber float64 `validate:"gte=5.56"` GteMultiple []string `validate:"gte=2"` GteTime time.Time `validate:"gte"` EqFieldString string `validate:"eqfield=MaxString"` EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"` NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"` GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"` GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"` LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"` LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"` NeFieldString string `validate:"nefield=EqFieldString"` GtFieldString string `validate:"gtfield=MaxString"` GteFieldString string `validate:"gtefield=MaxString"` LtFieldString string `validate:"ltfield=MaxString"` LteFieldString string `validate:"ltefield=MaxString"` AlphaString string `validate:"alpha"` AlphanumString string `validate:"alphanum"` NumericString string `validate:"numeric"` NumberString string `validate:"number"` HexadecimalString string `validate:"hexadecimal"` HexColorString string `validate:"hexcolor"` RGBColorString string `validate:"rgb"` RGBAColorString string `validate:"rgba"` HSLColorString string `validate:"hsl"` HSLAColorString string `validate:"hsla"` Email string `validate:"email"` URL string `validate:"url"` URI string `validate:"uri"` Base64 string `validate:"base64"` Contains string `validate:"contains=purpose"` ContainsAny string `validate:"containsany=!@#$"` Excludes string `validate:"excludes=text"` ExcludesAll string `validate:"excludesall=!@#$"` ExcludesRune string `validate:"excludesrune=☻"` ISBN string `validate:"isbn"` ISBN10 string `validate:"isbn10"` ISBN13 string `validate:"isbn13"` UUID string `validate:"uuid"` UUID3 string `validate:"uuid3"` UUID4 string `validate:"uuid4"` UUID5 string `validate:"uuid5"` ASCII string `validate:"ascii"` PrintableASCII string `validate:"printascii"` MultiByte string `validate:"multibyte"` DataURI string `validate:"datauri"` Latitude string `validate:"latitude"` Longitude string `validate:"longitude"` SSN string `validate:"ssn"` IP string `validate:"ip"` IPv4 string `validate:"ipv4"` IPv6 string `validate:"ipv6"` CIDR string `validate:"cidr"` CIDRv4 string `validate:"cidrv4"` CIDRv6 string `validate:"cidrv6"` TCPAddr string `validate:"tcp_addr"` TCPAddrv4 string `validate:"tcp4_addr"` TCPAddrv6 string `validate:"tcp6_addr"` UDPAddr string `validate:"udp_addr"` UDPAddrv4 string `validate:"udp4_addr"` UDPAddrv6 string `validate:"udp6_addr"` IPAddr string `validate:"ip_addr"` IPAddrv4 string `validate:"ip4_addr"` IPAddrv6 string `validate:"ip6_addr"` UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future MAC string `validate:"mac"` IsColor string `validate:"iscolor"` StrPtrMinLen *string `validate:"min=10"` StrPtrMaxLen *string `validate:"max=1"` StrPtrLen *string `validate:"len=2"` StrPtrLt *string `validate:"lt=1"` StrPtrLte *string `validate:"lte=1"` StrPtrGt *string `validate:"gt=10"` StrPtrGte *string `validate:"gte=10"` OneOfString string `validate:"oneof=red green"` OneOfInt int `validate:"oneof=5 63"` Datetime string `validate:"datetime=2006-01-02"` } var test Test test.Inner.EqCSFieldString = "1234" test.Inner.GtCSFieldString = "1234" test.Inner.GteCSFieldString = "1234" test.MaxString = "1234" test.MaxNumber = 2000 test.MaxMultiple = make([]string, 9) test.LtString = "1234" test.LtNumber = 6 test.LtMultiple = make([]string, 3) test.LtTime = time.Now().Add(time.Hour * 24) test.LteString = "1234" test.LteNumber = 6 test.LteMultiple = make([]string, 3) test.LteTime = time.Now().Add(time.Hour * 24) test.LtFieldString = "12345" test.LteFieldString = "12345" test.LtCSFieldString = "1234" test.LteCSFieldString = "1234" test.AlphaString = "abc3" test.AlphanumString = "abc3!" test.NumericString = "12E.00" test.NumberString = "12E" test.Excludes = "this is some test text" test.ExcludesAll = "This is Great!" test.ExcludesRune = "Love it ☻" test.ASCII = "カタカナ" test.PrintableASCII = "カタカナ" test.MultiByte = "1234feerf" s := "toolong" test.StrPtrMaxLen = &s test.StrPtrLen = &s test.Datetime = "2008-Feb-01" err = validate.Struct(test) NotEqual(t, err, nil) errs, ok := err.(validator.ValidationErrors) Equal(t, ok, true) tests := []struct { ns string expected string }{ { ns: "Test.IsColor", expected: "IsColor必須是一個有效的顏色", }, { ns: "Test.MAC", expected: "MAC必須是一個有效的MAC地址", }, { ns: "Test.IPAddr", expected: "IPAddr必須是一個有效的IP地址", }, { ns: "Test.IPAddrv4", expected: "IPAddrv4必須是一個有效的IPv4地址", }, { ns: "Test.IPAddrv6", expected: "IPAddrv6必須是一個有效的IPv6地址", }, { ns: "Test.UDPAddr", expected: "UDPAddr必須是一個有效的UDP地址", }, { ns: "Test.UDPAddrv4", expected: "UDPAddrv4必須是一個有效的IPv4 UDP地址", }, { ns: "Test.UDPAddrv6", expected: "UDPAddrv6必須是一個有效的IPv6 UDP地址", }, { ns: "Test.TCPAddr", expected: "TCPAddr必須是一個有效的TCP地址", }, { ns: "Test.TCPAddrv4", expected: "TCPAddrv4必須是一個有效的IPv4 TCP地址", }, { ns: "Test.TCPAddrv6", expected: "TCPAddrv6必須是一個有效的IPv6 TCP地址", }, { ns: "Test.CIDR", expected: "CIDR必須是一個有效的無類別域間路由(CIDR)", }, { ns: "Test.CIDRv4", expected: "CIDRv4必須是一个包含IPv4地址的有效無類別域間路由(CIDR)", }, { ns: "Test.CIDRv6", expected: "CIDRv6必須是一个包含IPv6地址的有效無類別域間路由(CIDR)", }, { ns: "Test.SSN", expected: "SSN必須是一個有效的社會安全編號(SSN)", }, { ns: "Test.IP", expected: "IP必須是一個有效的IP地址", }, { ns: "Test.IPv4", expected: "IPv4必須是一個有效的IPv4地址", }, { ns: "Test.IPv6", expected: "IPv6必須是一個有效的IPv6地址", }, { ns: "Test.DataURI", expected: "DataURI必須包含有效的數據URI", }, { ns: "Test.Latitude", expected: "Latitude必須包含有效的緯度座標", }, { ns: "Test.Longitude", expected: "Longitude必須包含有效的經度座標", }, { ns: "Test.MultiByte", expected: "MultiByte必須包含多個字元", }, { ns: "Test.ASCII", expected: "ASCII必須只包含ascii字元", }, { ns: "Test.PrintableASCII", expected: "PrintableASCII必須只包含可輸出的ascii字元", }, { ns: "Test.UUID", expected: "UUID必須是一個有效的UUID", }, { ns: "Test.UUID3", expected: "UUID3必須是一個有效的V3 UUID", }, { ns: "Test.UUID4", expected: "UUID4必須是一個有效的V4 UUID", }, { ns: "Test.UUID5", expected: "UUID5必須是一個有效的V5 UUID", }, { ns: "Test.ISBN", expected: "ISBN必須是一個有效的ISBN編號", }, { ns: "Test.ISBN10", expected: "ISBN10必須是一個有效的ISBN-10編號", }, { ns: "Test.ISBN13", expected: "ISBN13必須是一個有效的ISBN-13編號", }, { ns: "Test.Excludes", expected: "Excludes不能包含文字'text'", }, { ns: "Test.ExcludesAll", expected: "ExcludesAll不能包含以下任何字元'!@#$'", }, { ns: "Test.ExcludesRune", expected: "ExcludesRune不能包含'☻'", }, { ns: "Test.ContainsAny", expected: "ContainsAny必須包含至少一個以下字元'!@#$'", }, { ns: "Test.Contains", expected: "Contains必須包含文字'purpose'", }, { ns: "Test.Base64", expected: "Base64必須是一個有效的Base64字元串", }, { ns: "Test.Email", expected: "Email必須是一個有效的信箱", }, { ns: "Test.URL", expected: "URL必須是一個有效的URL", }, { ns: "Test.URI", expected: "URI必須是一個有效的URI", }, { ns: "Test.RGBColorString", expected: "RGBColorString必須是一個有效的RGB顏色", }, { ns: "Test.RGBAColorString", expected: "RGBAColorString必須是一個有效的RGBA顏色", }, { ns: "Test.HSLColorString", expected: "HSLColorString必須是一個有效的HSL顏色", }, { ns: "Test.HSLAColorString", expected: "HSLAColorString必須是一個有效的HSLA顏色", }, { ns: "Test.HexadecimalString", expected: "HexadecimalString必須是一個有效的十六進制", }, { ns: "Test.HexColorString", expected: "HexColorString必須是一個有效的十六進制顏色", }, { ns: "Test.NumberString", expected: "NumberString必須是一個有效的數字", }, { ns: "Test.NumericString", expected: "NumericString必須是一個有效的數值", }, { ns: "Test.AlphanumString", expected: "AlphanumString只能包含字母和數字", }, { ns: "Test.AlphaString", expected: "AlphaString只能包含字母", }, { ns: "Test.LtFieldString", expected: "LtFieldString必須小於MaxString", }, { ns: "Test.LteFieldString", expected: "LteFieldString必須小於或等於MaxString", }, { ns: "Test.GtFieldString", expected: "GtFieldString必須大於MaxString", }, { ns: "Test.GteFieldString", expected: "GteFieldString必須大於或等於MaxString", }, { ns: "Test.NeFieldString", expected: "NeFieldString不能等於EqFieldString", }, { ns: "Test.LtCSFieldString", expected: "LtCSFieldString必須小於Inner.LtCSFieldString", }, { ns: "Test.LteCSFieldString", expected: "LteCSFieldString必須小於或等於Inner.LteCSFieldString", }, { ns: "Test.GtCSFieldString", expected: "GtCSFieldString必須大於Inner.GtCSFieldString", }, { ns: "Test.GteCSFieldString", expected: "GteCSFieldString必須大於或等於Inner.GteCSFieldString", }, { ns: "Test.NeCSFieldString", expected: "NeCSFieldString不能等於Inner.NeCSFieldString", }, { ns: "Test.EqCSFieldString", expected: "EqCSFieldString必須等於Inner.EqCSFieldString", }, { ns: "Test.EqFieldString", expected: "EqFieldString必須等於MaxString", }, { ns: "Test.GteString", expected: "GteString長度必須至少為3個字元", }, { ns: "Test.GteNumber", expected: "GteNumber必須大於或等於5.56", }, { ns: "Test.GteMultiple", expected: "GteMultiple必須至少包含2項", }, { ns: "Test.GteTime", expected: "GteTime必須大於或等於目前日期和時間", }, { ns: "Test.GtString", expected: "GtString長度必須大於3個字元", }, { ns: "Test.GtNumber", expected: "GtNumber必須大於5.56", }, { ns: "Test.GtMultiple", expected: "GtMultiple必須大於2項", }, { ns: "Test.GtTime", expected: "GtTime必須大於目前日期和時間", }, { ns: "Test.LteString", expected: "LteString長度不能超過3個字元", }, { ns: "Test.LteNumber", expected: "LteNumber必須小於或等於5.56", }, { ns: "Test.LteMultiple", expected: "LteMultiple最多只能包含2項", }, { ns: "Test.LteTime", expected: "LteTime必須小於或等於目前日期和時間", }, { ns: "Test.LtString", expected: "LtString長度必須小於3個字元", }, { ns: "Test.LtNumber", expected: "LtNumber必須小於5.56", }, { ns: "Test.LtMultiple", expected: "LtMultiple必須包含少於2項", }, { ns: "Test.LtTime", expected: "LtTime必須小於目前日期和時間", }, { ns: "Test.NeString", expected: "NeString不能等於", }, { ns: "Test.NeNumber", expected: "NeNumber不能等於0.00", }, { ns: "Test.NeMultiple", expected: "NeMultiple不能等於0", }, { ns: "Test.EqString", expected: "EqString不等於3", }, { ns: "Test.EqNumber", expected: "EqNumber不等於2.33", }, { ns: "Test.EqMultiple", expected: "EqMultiple不等於7", }, { ns: "Test.MaxString", expected: "MaxString長度不能超過3個字元", }, { ns: "Test.MaxNumber", expected: "MaxNumber必須小於或等於1,113.00", }, { ns: "Test.MaxMultiple", expected: "MaxMultiple最多只能包含7項", }, { ns: "Test.MinString", expected: "MinString長度必須至少為1個字元", }, { ns: "Test.MinNumber", expected: "MinNumber最小只能為1,113.00", }, { ns: "Test.MinMultiple", expected: "MinMultiple必須至少包含7項", }, { ns: "Test.LenString", expected: "LenString長度必須為1個字元", }, { ns: "Test.LenNumber", expected: "LenNumber必須等於1,113.00", }, { ns: "Test.LenMultiple", expected: "LenMultiple必須包含7項", }, { ns: "Test.RequiredString", expected: "RequiredString為必填欄位", }, { ns: "Test.RequiredNumber", expected: "RequiredNumber為必填欄位", }, { ns: "Test.RequiredMultiple", expected: "RequiredMultiple為必填欄位", }, { ns: "Test.StrPtrMinLen", expected: "StrPtrMinLen長度必須至少為10個字元", }, { ns: "Test.StrPtrMaxLen", expected: "StrPtrMaxLen長度不能超過1個字元", }, { ns: "Test.StrPtrLen", expected: "StrPtrLen長度必須為2個字元", }, { ns: "Test.StrPtrLt", expected: "StrPtrLt長度必須小於1個字元", }, { ns: "Test.StrPtrLte", expected: "StrPtrLte長度不能超過1個字元", }, { ns: "Test.StrPtrGt", expected: "StrPtrGt長度必須大於10個字元", }, { ns: "Test.StrPtrGte", expected: "StrPtrGte長度必須至少為10個字元", }, { ns: "Test.OneOfString", expected: "OneOfString必須是[red green]中的一個", }, { ns: "Test.OneOfInt", expected: "OneOfInt必須是[5 63]中的一個", }, { ns: "Test.Datetime", expected: "Datetime與2006-01-02格式不匹配", }, } for _, tt := range tests { var fe validator.FieldError for _, e := range errs { if tt.ns == e.Namespace() { fe = e break } } NotEqual(t, fe, nil) Equal(t, tt.expected, fe.Translate(trans)) } } validator-10.4.1/util.go000066400000000000000000000145631374261122600151030ustar00rootroot00000000000000package validator import ( "reflect" "strconv" "strings" "time" ) // extractTypeInternal gets the actual underlying type of field value. // It will dive into pointers, customTypes and return you the // underlying value and it's kind. func (v *validate) extractTypeInternal(current reflect.Value, nullable bool) (reflect.Value, reflect.Kind, bool) { BEGIN: switch current.Kind() { case reflect.Ptr: nullable = true if current.IsNil() { return current, reflect.Ptr, nullable } current = current.Elem() goto BEGIN case reflect.Interface: nullable = true if current.IsNil() { return current, reflect.Interface, nullable } current = current.Elem() goto BEGIN case reflect.Invalid: return current, reflect.Invalid, nullable default: if v.v.hasCustomFuncs { if fn, ok := v.v.customFuncs[current.Type()]; ok { current = reflect.ValueOf(fn(current)) goto BEGIN } } return current, current.Kind(), nullable } } // getStructFieldOKInternal traverses a struct to retrieve a specific field denoted by the provided namespace and // returns the field, field kind and whether is was successful in retrieving the field at all. // // NOTE: when not successful ok will be false, this can happen when a nested struct is nil and so the field // could not be retrieved because it didn't exist. func (v *validate) getStructFieldOKInternal(val reflect.Value, namespace string) (current reflect.Value, kind reflect.Kind, nullable bool, found bool) { BEGIN: current, kind, nullable = v.ExtractType(val) if kind == reflect.Invalid { return } if namespace == "" { found = true return } switch kind { case reflect.Ptr, reflect.Interface: return case reflect.Struct: typ := current.Type() fld := namespace var ns string if typ != timeType { idx := strings.Index(namespace, namespaceSeparator) if idx != -1 { fld = namespace[:idx] ns = namespace[idx+1:] } else { ns = "" } bracketIdx := strings.Index(fld, leftBracket) if bracketIdx != -1 { fld = fld[:bracketIdx] ns = namespace[bracketIdx:] } val = current.FieldByName(fld) namespace = ns goto BEGIN } case reflect.Array, reflect.Slice: idx := strings.Index(namespace, leftBracket) idx2 := strings.Index(namespace, rightBracket) arrIdx, _ := strconv.Atoi(namespace[idx+1 : idx2]) if arrIdx >= current.Len() { return } startIdx := idx2 + 1 if startIdx < len(namespace) { if namespace[startIdx:startIdx+1] == namespaceSeparator { startIdx++ } } val = current.Index(arrIdx) namespace = namespace[startIdx:] goto BEGIN case reflect.Map: idx := strings.Index(namespace, leftBracket) + 1 idx2 := strings.Index(namespace, rightBracket) endIdx := idx2 if endIdx+1 < len(namespace) { if namespace[endIdx+1:endIdx+2] == namespaceSeparator { endIdx++ } } key := namespace[idx:idx2] switch current.Type().Key().Kind() { case reflect.Int: i, _ := strconv.Atoi(key) val = current.MapIndex(reflect.ValueOf(i)) namespace = namespace[endIdx+1:] case reflect.Int8: i, _ := strconv.ParseInt(key, 10, 8) val = current.MapIndex(reflect.ValueOf(int8(i))) namespace = namespace[endIdx+1:] case reflect.Int16: i, _ := strconv.ParseInt(key, 10, 16) val = current.MapIndex(reflect.ValueOf(int16(i))) namespace = namespace[endIdx+1:] case reflect.Int32: i, _ := strconv.ParseInt(key, 10, 32) val = current.MapIndex(reflect.ValueOf(int32(i))) namespace = namespace[endIdx+1:] case reflect.Int64: i, _ := strconv.ParseInt(key, 10, 64) val = current.MapIndex(reflect.ValueOf(i)) namespace = namespace[endIdx+1:] case reflect.Uint: i, _ := strconv.ParseUint(key, 10, 0) val = current.MapIndex(reflect.ValueOf(uint(i))) namespace = namespace[endIdx+1:] case reflect.Uint8: i, _ := strconv.ParseUint(key, 10, 8) val = current.MapIndex(reflect.ValueOf(uint8(i))) namespace = namespace[endIdx+1:] case reflect.Uint16: i, _ := strconv.ParseUint(key, 10, 16) val = current.MapIndex(reflect.ValueOf(uint16(i))) namespace = namespace[endIdx+1:] case reflect.Uint32: i, _ := strconv.ParseUint(key, 10, 32) val = current.MapIndex(reflect.ValueOf(uint32(i))) namespace = namespace[endIdx+1:] case reflect.Uint64: i, _ := strconv.ParseUint(key, 10, 64) val = current.MapIndex(reflect.ValueOf(i)) namespace = namespace[endIdx+1:] case reflect.Float32: f, _ := strconv.ParseFloat(key, 32) val = current.MapIndex(reflect.ValueOf(float32(f))) namespace = namespace[endIdx+1:] case reflect.Float64: f, _ := strconv.ParseFloat(key, 64) val = current.MapIndex(reflect.ValueOf(f)) namespace = namespace[endIdx+1:] case reflect.Bool: b, _ := strconv.ParseBool(key) val = current.MapIndex(reflect.ValueOf(b)) namespace = namespace[endIdx+1:] // reflect.Type = string default: val = current.MapIndex(reflect.ValueOf(key)) namespace = namespace[endIdx+1:] } goto BEGIN } // if got here there was more namespace, cannot go any deeper panic("Invalid field namespace") } // asInt returns the parameter as a int64 // or panics if it can't convert func asInt(param string) int64 { i, err := strconv.ParseInt(param, 0, 64) panicIf(err) return i } // asIntFromTimeDuration parses param as time.Duration and returns it as int64 // or panics on error. func asIntFromTimeDuration(param string) int64 { d, err := time.ParseDuration(param) if err != nil { // attempt parsing as an an integer assuming nanosecond precision return asInt(param) } return int64(d) } // asIntFromType calls the proper function to parse param as int64, // given a field's Type t. func asIntFromType(t reflect.Type, param string) int64 { switch t { case timeDurationType: return asIntFromTimeDuration(param) default: return asInt(param) } } // asUint returns the parameter as a uint64 // or panics if it can't convert func asUint(param string) uint64 { i, err := strconv.ParseUint(param, 0, 64) panicIf(err) return i } // asFloat returns the parameter as a float64 // or panics if it can't convert func asFloat(param string) float64 { i, err := strconv.ParseFloat(param, 64) panicIf(err) return i } // asBool returns the parameter as a bool // or panics if it can't convert func asBool(param string) bool { i, err := strconv.ParseBool(param) panicIf(err) return i } func panicIf(err error) { if err != nil { panic(err.Error()) } } validator-10.4.1/validator.go000066400000000000000000000256221374261122600161110ustar00rootroot00000000000000package validator import ( "context" "fmt" "reflect" "strconv" ) // per validate construct type validate struct { v *Validate top reflect.Value ns []byte actualNs []byte errs ValidationErrors includeExclude map[string]struct{} // reset only if StructPartial or StructExcept are called, no need otherwise ffn FilterFunc slflParent reflect.Value // StructLevel & FieldLevel slCurrent reflect.Value // StructLevel & FieldLevel flField reflect.Value // StructLevel & FieldLevel cf *cField // StructLevel & FieldLevel ct *cTag // StructLevel & FieldLevel misc []byte // misc reusable str1 string // misc reusable str2 string // misc reusable fldIsPointer bool // StructLevel & FieldLevel isPartial bool hasExcludes bool } // parent and current will be the same the first run of validateStruct func (v *validate) validateStruct(ctx context.Context, parent reflect.Value, current reflect.Value, typ reflect.Type, ns []byte, structNs []byte, ct *cTag) { cs, ok := v.v.structCache.Get(typ) if !ok { cs = v.v.extractStructCache(current, typ.Name()) } if len(ns) == 0 && len(cs.name) != 0 { ns = append(ns, cs.name...) ns = append(ns, '.') structNs = append(structNs, cs.name...) structNs = append(structNs, '.') } // ct is nil on top level struct, and structs as fields that have no tag info // so if nil or if not nil and the structonly tag isn't present if ct == nil || ct.typeof != typeStructOnly { var f *cField for i := 0; i < len(cs.fields); i++ { f = cs.fields[i] if v.isPartial { if v.ffn != nil { // used with StructFiltered if v.ffn(append(structNs, f.name...)) { continue } } else { // used with StructPartial & StructExcept _, ok = v.includeExclude[string(append(structNs, f.name...))] if (ok && v.hasExcludes) || (!ok && !v.hasExcludes) { continue } } } v.traverseField(ctx, parent, current.Field(f.idx), ns, structNs, f, f.cTags) } } // check if any struct level validations, after all field validations already checked. // first iteration will have no info about nostructlevel tag, and is checked prior to // calling the next iteration of validateStruct called from traverseField. if cs.fn != nil { v.slflParent = parent v.slCurrent = current v.ns = ns v.actualNs = structNs cs.fn(ctx, v) } } // traverseField validates any field, be it a struct or single field, ensures it's validity and passes it along to be validated via it's tag options func (v *validate) traverseField(ctx context.Context, parent reflect.Value, current reflect.Value, ns []byte, structNs []byte, cf *cField, ct *cTag) { var typ reflect.Type var kind reflect.Kind current, kind, v.fldIsPointer = v.extractTypeInternal(current, false) switch kind { case reflect.Ptr, reflect.Interface, reflect.Invalid: if ct == nil { return } if ct.typeof == typeOmitEmpty || ct.typeof == typeIsDefault { return } if ct.hasTag { if kind == reflect.Invalid { v.str1 = string(append(ns, cf.altName...)) if v.v.hasTagNameFunc { v.str2 = string(append(structNs, cf.name...)) } else { v.str2 = v.str1 } v.errs = append(v.errs, &fieldError{ v: v.v, tag: ct.aliasTag, actualTag: ct.tag, ns: v.str1, structNs: v.str2, fieldLen: uint8(len(cf.altName)), structfieldLen: uint8(len(cf.name)), param: ct.param, kind: kind, }, ) return } v.str1 = string(append(ns, cf.altName...)) if v.v.hasTagNameFunc { v.str2 = string(append(structNs, cf.name...)) } else { v.str2 = v.str1 } if !ct.runValidationWhenNil { v.errs = append(v.errs, &fieldError{ v: v.v, tag: ct.aliasTag, actualTag: ct.tag, ns: v.str1, structNs: v.str2, fieldLen: uint8(len(cf.altName)), structfieldLen: uint8(len(cf.name)), value: current.Interface(), param: ct.param, kind: kind, typ: current.Type(), }, ) return } } case reflect.Struct: typ = current.Type() if typ != timeType { if ct != nil { if ct.typeof == typeStructOnly { goto CONTINUE } else if ct.typeof == typeIsDefault { // set Field Level fields v.slflParent = parent v.flField = current v.cf = cf v.ct = ct if !ct.fn(ctx, v) { v.str1 = string(append(ns, cf.altName...)) if v.v.hasTagNameFunc { v.str2 = string(append(structNs, cf.name...)) } else { v.str2 = v.str1 } v.errs = append(v.errs, &fieldError{ v: v.v, tag: ct.aliasTag, actualTag: ct.tag, ns: v.str1, structNs: v.str2, fieldLen: uint8(len(cf.altName)), structfieldLen: uint8(len(cf.name)), value: current.Interface(), param: ct.param, kind: kind, typ: typ, }, ) return } } ct = ct.next } if ct != nil && ct.typeof == typeNoStructLevel { return } CONTINUE: // if len == 0 then validating using 'Var' or 'VarWithValue' // Var - doesn't make much sense to do it that way, should call 'Struct', but no harm... // VarWithField - this allows for validating against each field within the struct against a specific value // pretty handy in certain situations if len(cf.name) > 0 { ns = append(append(ns, cf.altName...), '.') structNs = append(append(structNs, cf.name...), '.') } v.validateStruct(ctx, current, current, typ, ns, structNs, ct) return } } if !ct.hasTag { return } typ = current.Type() OUTER: for { if ct == nil { return } switch ct.typeof { case typeOmitEmpty: // set Field Level fields v.slflParent = parent v.flField = current v.cf = cf v.ct = ct if !hasValue(v) { return } ct = ct.next continue case typeEndKeys: return case typeDive: ct = ct.next // traverse slice or map here // or panic ;) switch kind { case reflect.Slice, reflect.Array: var i64 int64 reusableCF := &cField{} for i := 0; i < current.Len(); i++ { i64 = int64(i) v.misc = append(v.misc[0:0], cf.name...) v.misc = append(v.misc, '[') v.misc = strconv.AppendInt(v.misc, i64, 10) v.misc = append(v.misc, ']') reusableCF.name = string(v.misc) if cf.namesEqual { reusableCF.altName = reusableCF.name } else { v.misc = append(v.misc[0:0], cf.altName...) v.misc = append(v.misc, '[') v.misc = strconv.AppendInt(v.misc, i64, 10) v.misc = append(v.misc, ']') reusableCF.altName = string(v.misc) } v.traverseField(ctx, parent, current.Index(i), ns, structNs, reusableCF, ct) } case reflect.Map: var pv string reusableCF := &cField{} for _, key := range current.MapKeys() { pv = fmt.Sprintf("%v", key.Interface()) v.misc = append(v.misc[0:0], cf.name...) v.misc = append(v.misc, '[') v.misc = append(v.misc, pv...) v.misc = append(v.misc, ']') reusableCF.name = string(v.misc) if cf.namesEqual { reusableCF.altName = reusableCF.name } else { v.misc = append(v.misc[0:0], cf.altName...) v.misc = append(v.misc, '[') v.misc = append(v.misc, pv...) v.misc = append(v.misc, ']') reusableCF.altName = string(v.misc) } if ct != nil && ct.typeof == typeKeys && ct.keys != nil { v.traverseField(ctx, parent, key, ns, structNs, reusableCF, ct.keys) // can be nil when just keys being validated if ct.next != nil { v.traverseField(ctx, parent, current.MapIndex(key), ns, structNs, reusableCF, ct.next) } } else { v.traverseField(ctx, parent, current.MapIndex(key), ns, structNs, reusableCF, ct) } } default: // throw error, if not a slice or map then should not have gotten here // bad dive tag panic("dive error! can't dive on a non slice or map") } return case typeOr: v.misc = v.misc[0:0] for { // set Field Level fields v.slflParent = parent v.flField = current v.cf = cf v.ct = ct if ct.fn(ctx, v) { // drain rest of the 'or' values, then continue or leave for { ct = ct.next if ct == nil { return } if ct.typeof != typeOr { continue OUTER } } } v.misc = append(v.misc, '|') v.misc = append(v.misc, ct.tag...) if ct.hasParam { v.misc = append(v.misc, '=') v.misc = append(v.misc, ct.param...) } if ct.isBlockEnd || ct.next == nil { // if we get here, no valid 'or' value and no more tags v.str1 = string(append(ns, cf.altName...)) if v.v.hasTagNameFunc { v.str2 = string(append(structNs, cf.name...)) } else { v.str2 = v.str1 } if ct.hasAlias { v.errs = append(v.errs, &fieldError{ v: v.v, tag: ct.aliasTag, actualTag: ct.actualAliasTag, ns: v.str1, structNs: v.str2, fieldLen: uint8(len(cf.altName)), structfieldLen: uint8(len(cf.name)), value: current.Interface(), param: ct.param, kind: kind, typ: typ, }, ) } else { tVal := string(v.misc)[1:] v.errs = append(v.errs, &fieldError{ v: v.v, tag: tVal, actualTag: tVal, ns: v.str1, structNs: v.str2, fieldLen: uint8(len(cf.altName)), structfieldLen: uint8(len(cf.name)), value: current.Interface(), param: ct.param, kind: kind, typ: typ, }, ) } return } ct = ct.next } default: // set Field Level fields v.slflParent = parent v.flField = current v.cf = cf v.ct = ct if !ct.fn(ctx, v) { v.str1 = string(append(ns, cf.altName...)) if v.v.hasTagNameFunc { v.str2 = string(append(structNs, cf.name...)) } else { v.str2 = v.str1 } v.errs = append(v.errs, &fieldError{ v: v.v, tag: ct.aliasTag, actualTag: ct.tag, ns: v.str1, structNs: v.str2, fieldLen: uint8(len(cf.altName)), structfieldLen: uint8(len(cf.name)), value: current.Interface(), param: ct.param, kind: kind, typ: typ, }, ) return } ct = ct.next } } } validator-10.4.1/validator_instance.go000066400000000000000000000514331374261122600177740ustar00rootroot00000000000000package validator import ( "context" "errors" "fmt" "reflect" "strings" "sync" "time" ut "github.com/go-playground/universal-translator" ) const ( defaultTagName = "validate" utf8HexComma = "0x2C" utf8Pipe = "0x7C" tagSeparator = "," orSeparator = "|" tagKeySeparator = "=" structOnlyTag = "structonly" noStructLevelTag = "nostructlevel" omitempty = "omitempty" isdefault = "isdefault" requiredWithoutAllTag = "required_without_all" requiredWithoutTag = "required_without" requiredWithTag = "required_with" requiredWithAllTag = "required_with_all" requiredIfTag = "required_if" requiredUnlessTag = "required_unless" skipValidationTag = "-" diveTag = "dive" keysTag = "keys" endKeysTag = "endkeys" requiredTag = "required" namespaceSeparator = "." leftBracket = "[" rightBracket = "]" restrictedTagChars = ".[],|=+()`~!@#$%^&*\\\"/?<>{}" restrictedAliasErr = "Alias '%s' either contains restricted characters or is the same as a restricted tag needed for normal operation" restrictedTagErr = "Tag '%s' either contains restricted characters or is the same as a restricted tag needed for normal operation" ) var ( timeDurationType = reflect.TypeOf(time.Duration(0)) timeType = reflect.TypeOf(time.Time{}) defaultCField = &cField{namesEqual: true} ) // FilterFunc is the type used to filter fields using // StructFiltered(...) function. // returning true results in the field being filtered/skiped from // validation type FilterFunc func(ns []byte) bool // CustomTypeFunc allows for overriding or adding custom field type handler functions // field = field value of the type to return a value to be validated // example Valuer from sql drive see https://golang.org/src/database/sql/driver/types.go?s=1210:1293#L29 type CustomTypeFunc func(field reflect.Value) interface{} // TagNameFunc allows for adding of a custom tag name parser type TagNameFunc func(field reflect.StructField) string type internalValidationFuncWrapper struct { fn FuncCtx runValidatinOnNil bool } // Validate contains the validator settings and cache type Validate struct { tagName string pool *sync.Pool hasCustomFuncs bool hasTagNameFunc bool tagNameFunc TagNameFunc structLevelFuncs map[reflect.Type]StructLevelFuncCtx customFuncs map[reflect.Type]CustomTypeFunc aliases map[string]string validations map[string]internalValidationFuncWrapper transTagFunc map[ut.Translator]map[string]TranslationFunc // map[]map[]TranslationFunc tagCache *tagCache structCache *structCache } // New returns a new instance of 'validate' with sane defaults. func New() *Validate { tc := new(tagCache) tc.m.Store(make(map[string]*cTag)) sc := new(structCache) sc.m.Store(make(map[reflect.Type]*cStruct)) v := &Validate{ tagName: defaultTagName, aliases: make(map[string]string, len(bakedInAliases)), validations: make(map[string]internalValidationFuncWrapper, len(bakedInValidators)), tagCache: tc, structCache: sc, } // must copy alias validators for separate validations to be used in each validator instance for k, val := range bakedInAliases { v.RegisterAlias(k, val) } // must copy validators for separate validations to be used in each instance for k, val := range bakedInValidators { switch k { // these require that even if the value is nil that the validation should run, omitempty still overrides this behaviour case requiredIfTag, requiredUnlessTag, requiredWithTag, requiredWithAllTag, requiredWithoutTag, requiredWithoutAllTag: _ = v.registerValidation(k, wrapFunc(val), true, true) default: // no need to error check here, baked in will always be valid _ = v.registerValidation(k, wrapFunc(val), true, false) } } v.pool = &sync.Pool{ New: func() interface{} { return &validate{ v: v, ns: make([]byte, 0, 64), actualNs: make([]byte, 0, 64), misc: make([]byte, 32), } }, } return v } // SetTagName allows for changing of the default tag name of 'validate' func (v *Validate) SetTagName(name string) { v.tagName = name } // RegisterTagNameFunc registers a function to get alternate names for StructFields. // // eg. to use the names which have been specified for JSON representations of structs, rather than normal Go field names: // // validate.RegisterTagNameFunc(func(fld reflect.StructField) string { // name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] // if name == "-" { // return "" // } // return name // }) func (v *Validate) RegisterTagNameFunc(fn TagNameFunc) { v.tagNameFunc = fn v.hasTagNameFunc = true } // RegisterValidation adds a validation with the given tag // // NOTES: // - if the key already exists, the previous validation function will be replaced. // - this method is not thread-safe it is intended that these all be registered prior to any validation func (v *Validate) RegisterValidation(tag string, fn Func, callValidationEvenIfNull ...bool) error { return v.RegisterValidationCtx(tag, wrapFunc(fn), callValidationEvenIfNull...) } // RegisterValidationCtx does the same as RegisterValidation on accepts a FuncCtx validation // allowing context.Context validation support. func (v *Validate) RegisterValidationCtx(tag string, fn FuncCtx, callValidationEvenIfNull ...bool) error { var nilCheckable bool if len(callValidationEvenIfNull) > 0 { nilCheckable = callValidationEvenIfNull[0] } return v.registerValidation(tag, fn, false, nilCheckable) } func (v *Validate) registerValidation(tag string, fn FuncCtx, bakedIn bool, nilCheckable bool) error { if len(tag) == 0 { return errors.New("Function Key cannot be empty") } if fn == nil { return errors.New("Function cannot be empty") } _, ok := restrictedTags[tag] if !bakedIn && (ok || strings.ContainsAny(tag, restrictedTagChars)) { panic(fmt.Sprintf(restrictedTagErr, tag)) } v.validations[tag] = internalValidationFuncWrapper{fn: fn, runValidatinOnNil: nilCheckable} return nil } // RegisterAlias registers a mapping of a single validation tag that // defines a common or complex set of validation(s) to simplify adding validation // to structs. // // NOTE: this function is not thread-safe it is intended that these all be registered prior to any validation func (v *Validate) RegisterAlias(alias, tags string) { _, ok := restrictedTags[alias] if ok || strings.ContainsAny(alias, restrictedTagChars) { panic(fmt.Sprintf(restrictedAliasErr, alias)) } v.aliases[alias] = tags } // RegisterStructValidation registers a StructLevelFunc against a number of types. // // NOTE: // - this method is not thread-safe it is intended that these all be registered prior to any validation func (v *Validate) RegisterStructValidation(fn StructLevelFunc, types ...interface{}) { v.RegisterStructValidationCtx(wrapStructLevelFunc(fn), types...) } // RegisterStructValidationCtx registers a StructLevelFuncCtx against a number of types and allows passing // of contextual validation information via context.Context. // // NOTE: // - this method is not thread-safe it is intended that these all be registered prior to any validation func (v *Validate) RegisterStructValidationCtx(fn StructLevelFuncCtx, types ...interface{}) { if v.structLevelFuncs == nil { v.structLevelFuncs = make(map[reflect.Type]StructLevelFuncCtx) } for _, t := range types { tv := reflect.ValueOf(t) if tv.Kind() == reflect.Ptr { t = reflect.Indirect(tv).Interface() } v.structLevelFuncs[reflect.TypeOf(t)] = fn } } // RegisterCustomTypeFunc registers a CustomTypeFunc against a number of types // // NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation func (v *Validate) RegisterCustomTypeFunc(fn CustomTypeFunc, types ...interface{}) { if v.customFuncs == nil { v.customFuncs = make(map[reflect.Type]CustomTypeFunc) } for _, t := range types { v.customFuncs[reflect.TypeOf(t)] = fn } v.hasCustomFuncs = true } // RegisterTranslation registers translations against the provided tag. func (v *Validate) RegisterTranslation(tag string, trans ut.Translator, registerFn RegisterTranslationsFunc, translationFn TranslationFunc) (err error) { if v.transTagFunc == nil { v.transTagFunc = make(map[ut.Translator]map[string]TranslationFunc) } if err = registerFn(trans); err != nil { return } m, ok := v.transTagFunc[trans] if !ok { m = make(map[string]TranslationFunc) v.transTagFunc[trans] = m } m[tag] = translationFn return } // Struct validates a structs exposed fields, and automatically validates nested structs, unless otherwise specified. // // It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. func (v *Validate) Struct(s interface{}) error { return v.StructCtx(context.Background(), s) } // StructCtx validates a structs exposed fields, and automatically validates nested structs, unless otherwise specified // and also allows passing of context.Context for contextual validation information. // // It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. func (v *Validate) StructCtx(ctx context.Context, s interface{}) (err error) { val := reflect.ValueOf(s) top := val if val.Kind() == reflect.Ptr && !val.IsNil() { val = val.Elem() } if val.Kind() != reflect.Struct || val.Type() == timeType { return &InvalidValidationError{Type: reflect.TypeOf(s)} } // good to validate vd := v.pool.Get().(*validate) vd.top = top vd.isPartial = false // vd.hasExcludes = false // only need to reset in StructPartial and StructExcept vd.validateStruct(ctx, top, val, val.Type(), vd.ns[0:0], vd.actualNs[0:0], nil) if len(vd.errs) > 0 { err = vd.errs vd.errs = nil } v.pool.Put(vd) return } // StructFiltered validates a structs exposed fields, that pass the FilterFunc check and automatically validates // nested structs, unless otherwise specified. // // It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. func (v *Validate) StructFiltered(s interface{}, fn FilterFunc) error { return v.StructFilteredCtx(context.Background(), s, fn) } // StructFilteredCtx validates a structs exposed fields, that pass the FilterFunc check and automatically validates // nested structs, unless otherwise specified and also allows passing of contextual validation information via // context.Context // // It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. func (v *Validate) StructFilteredCtx(ctx context.Context, s interface{}, fn FilterFunc) (err error) { val := reflect.ValueOf(s) top := val if val.Kind() == reflect.Ptr && !val.IsNil() { val = val.Elem() } if val.Kind() != reflect.Struct || val.Type() == timeType { return &InvalidValidationError{Type: reflect.TypeOf(s)} } // good to validate vd := v.pool.Get().(*validate) vd.top = top vd.isPartial = true vd.ffn = fn // vd.hasExcludes = false // only need to reset in StructPartial and StructExcept vd.validateStruct(ctx, top, val, val.Type(), vd.ns[0:0], vd.actualNs[0:0], nil) if len(vd.errs) > 0 { err = vd.errs vd.errs = nil } v.pool.Put(vd) return } // StructPartial validates the fields passed in only, ignoring all others. // Fields may be provided in a namespaced fashion relative to the struct provided // eg. NestedStruct.Field or NestedArrayField[0].Struct.Name // // It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. func (v *Validate) StructPartial(s interface{}, fields ...string) error { return v.StructPartialCtx(context.Background(), s, fields...) } // StructPartialCtx validates the fields passed in only, ignoring all others and allows passing of contextual // validation validation information via context.Context // Fields may be provided in a namespaced fashion relative to the struct provided // eg. NestedStruct.Field or NestedArrayField[0].Struct.Name // // It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. func (v *Validate) StructPartialCtx(ctx context.Context, s interface{}, fields ...string) (err error) { val := reflect.ValueOf(s) top := val if val.Kind() == reflect.Ptr && !val.IsNil() { val = val.Elem() } if val.Kind() != reflect.Struct || val.Type() == timeType { return &InvalidValidationError{Type: reflect.TypeOf(s)} } // good to validate vd := v.pool.Get().(*validate) vd.top = top vd.isPartial = true vd.ffn = nil vd.hasExcludes = false vd.includeExclude = make(map[string]struct{}) typ := val.Type() name := typ.Name() for _, k := range fields { flds := strings.Split(k, namespaceSeparator) if len(flds) > 0 { vd.misc = append(vd.misc[0:0], name...) vd.misc = append(vd.misc, '.') for _, s := range flds { idx := strings.Index(s, leftBracket) if idx != -1 { for idx != -1 { vd.misc = append(vd.misc, s[:idx]...) vd.includeExclude[string(vd.misc)] = struct{}{} idx2 := strings.Index(s, rightBracket) idx2++ vd.misc = append(vd.misc, s[idx:idx2]...) vd.includeExclude[string(vd.misc)] = struct{}{} s = s[idx2:] idx = strings.Index(s, leftBracket) } } else { vd.misc = append(vd.misc, s...) vd.includeExclude[string(vd.misc)] = struct{}{} } vd.misc = append(vd.misc, '.') } } } vd.validateStruct(ctx, top, val, typ, vd.ns[0:0], vd.actualNs[0:0], nil) if len(vd.errs) > 0 { err = vd.errs vd.errs = nil } v.pool.Put(vd) return } // StructExcept validates all fields except the ones passed in. // Fields may be provided in a namespaced fashion relative to the struct provided // i.e. NestedStruct.Field or NestedArrayField[0].Struct.Name // // It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. func (v *Validate) StructExcept(s interface{}, fields ...string) error { return v.StructExceptCtx(context.Background(), s, fields...) } // StructExceptCtx validates all fields except the ones passed in and allows passing of contextual // validation validation information via context.Context // Fields may be provided in a namespaced fashion relative to the struct provided // i.e. NestedStruct.Field or NestedArrayField[0].Struct.Name // // It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. func (v *Validate) StructExceptCtx(ctx context.Context, s interface{}, fields ...string) (err error) { val := reflect.ValueOf(s) top := val if val.Kind() == reflect.Ptr && !val.IsNil() { val = val.Elem() } if val.Kind() != reflect.Struct || val.Type() == timeType { return &InvalidValidationError{Type: reflect.TypeOf(s)} } // good to validate vd := v.pool.Get().(*validate) vd.top = top vd.isPartial = true vd.ffn = nil vd.hasExcludes = true vd.includeExclude = make(map[string]struct{}) typ := val.Type() name := typ.Name() for _, key := range fields { vd.misc = vd.misc[0:0] if len(name) > 0 { vd.misc = append(vd.misc, name...) vd.misc = append(vd.misc, '.') } vd.misc = append(vd.misc, key...) vd.includeExclude[string(vd.misc)] = struct{}{} } vd.validateStruct(ctx, top, val, typ, vd.ns[0:0], vd.actualNs[0:0], nil) if len(vd.errs) > 0 { err = vd.errs vd.errs = nil } v.pool.Put(vd) return } // Var validates a single variable using tag style validation. // eg. // var i int // validate.Var(i, "gt=1,lt=10") // // WARNING: a struct can be passed for validation eg. time.Time is a struct or // if you have a custom type and have registered a custom type handler, so must // allow it; however unforeseen validations will occur if trying to validate a // struct that is meant to be passed to 'validate.Struct' // // It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. // validate Array, Slice and maps fields which may contain more than one error func (v *Validate) Var(field interface{}, tag string) error { return v.VarCtx(context.Background(), field, tag) } // VarCtx validates a single variable using tag style validation and allows passing of contextual // validation validation information via context.Context. // eg. // var i int // validate.Var(i, "gt=1,lt=10") // // WARNING: a struct can be passed for validation eg. time.Time is a struct or // if you have a custom type and have registered a custom type handler, so must // allow it; however unforeseen validations will occur if trying to validate a // struct that is meant to be passed to 'validate.Struct' // // It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. // validate Array, Slice and maps fields which may contain more than one error func (v *Validate) VarCtx(ctx context.Context, field interface{}, tag string) (err error) { if len(tag) == 0 || tag == skipValidationTag { return nil } ctag := v.fetchCacheTag(tag) val := reflect.ValueOf(field) vd := v.pool.Get().(*validate) vd.top = val vd.isPartial = false vd.traverseField(ctx, val, val, vd.ns[0:0], vd.actualNs[0:0], defaultCField, ctag) if len(vd.errs) > 0 { err = vd.errs vd.errs = nil } v.pool.Put(vd) return } // VarWithValue validates a single variable, against another variable/field's value using tag style validation // eg. // s1 := "abcd" // s2 := "abcd" // validate.VarWithValue(s1, s2, "eqcsfield") // returns true // // WARNING: a struct can be passed for validation eg. time.Time is a struct or // if you have a custom type and have registered a custom type handler, so must // allow it; however unforeseen validations will occur if trying to validate a // struct that is meant to be passed to 'validate.Struct' // // It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. // validate Array, Slice and maps fields which may contain more than one error func (v *Validate) VarWithValue(field interface{}, other interface{}, tag string) error { return v.VarWithValueCtx(context.Background(), field, other, tag) } // VarWithValueCtx validates a single variable, against another variable/field's value using tag style validation and // allows passing of contextual validation validation information via context.Context. // eg. // s1 := "abcd" // s2 := "abcd" // validate.VarWithValue(s1, s2, "eqcsfield") // returns true // // WARNING: a struct can be passed for validation eg. time.Time is a struct or // if you have a custom type and have registered a custom type handler, so must // allow it; however unforeseen validations will occur if trying to validate a // struct that is meant to be passed to 'validate.Struct' // // It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. // validate Array, Slice and maps fields which may contain more than one error func (v *Validate) VarWithValueCtx(ctx context.Context, field interface{}, other interface{}, tag string) (err error) { if len(tag) == 0 || tag == skipValidationTag { return nil } ctag := v.fetchCacheTag(tag) otherVal := reflect.ValueOf(other) vd := v.pool.Get().(*validate) vd.top = otherVal vd.isPartial = false vd.traverseField(ctx, otherVal, reflect.ValueOf(field), vd.ns[0:0], vd.actualNs[0:0], defaultCField, ctag) if len(vd.errs) > 0 { err = vd.errs vd.errs = nil } v.pool.Put(vd) return } validator-10.4.1/validator_test.go000066400000000000000000010733341374261122600171540ustar00rootroot00000000000000package validator import ( "bytes" "context" "database/sql" "database/sql/driver" "encoding/base64" "encoding/json" "fmt" "path/filepath" "reflect" "strings" "testing" "time" . "github.com/go-playground/assert/v2" "github.com/go-playground/locales/en" "github.com/go-playground/locales/fr" "github.com/go-playground/locales/nl" ut "github.com/go-playground/universal-translator" ) // NOTES: // - Run "go test" to run tests // - Run "gocov test | gocov report" to report on test converage by file // - Run "gocov test | gocov annotate -" to report on all code and functions, those ,marked with "MISS" were never called // // or // // -- may be a good idea to change to output path to somewherelike /tmp // go test -coverprofile cover.out && go tool cover -html=cover.out -o cover.html // // // go test -cpuprofile cpu.out // ./validator.test -test.bench=. -test.cpuprofile=cpu.prof // go tool pprof validator.test cpu.prof // // // go test -memprofile mem.out type I interface { Foo() string } type Impl struct { F string `validate:"len=3"` } func (i *Impl) Foo() string { return i.F } type SubTest struct { Test string `validate:"required"` } type TestInterface struct { Iface I } type TestString struct { BlankTag string `validate:""` Required string `validate:"required"` Len string `validate:"len=10"` Min string `validate:"min=1"` Max string `validate:"max=10"` MinMax string `validate:"min=1,max=10"` Lt string `validate:"lt=10"` Lte string `validate:"lte=10"` Gt string `validate:"gt=10"` Gte string `validate:"gte=10"` OmitEmpty string `validate:"omitempty,min=1,max=10"` Sub *SubTest SubIgnore *SubTest `validate:"-"` Anonymous struct { A string `validate:"required"` } Iface I } type TestUint64 struct { Required uint64 `validate:"required"` Len uint64 `validate:"len=10"` Min uint64 `validate:"min=1"` Max uint64 `validate:"max=10"` MinMax uint64 `validate:"min=1,max=10"` OmitEmpty uint64 `validate:"omitempty,min=1,max=10"` } type TestFloat64 struct { Required float64 `validate:"required"` Len float64 `validate:"len=10"` Min float64 `validate:"min=1"` Max float64 `validate:"max=10"` MinMax float64 `validate:"min=1,max=10"` Lte float64 `validate:"lte=10"` OmitEmpty float64 `validate:"omitempty,min=1,max=10"` } type TestSlice struct { Required []int `validate:"required"` Len []int `validate:"len=10"` Min []int `validate:"min=1"` Max []int `validate:"max=10"` MinMax []int `validate:"min=1,max=10"` OmitEmpty []int `validate:"omitempty,min=1,max=10"` } func AssertError(t *testing.T, err error, nsKey, structNsKey, field, structField, expectedTag string) { errs := err.(ValidationErrors) found := false var fe FieldError for i := 0; i < len(errs); i++ { if errs[i].Namespace() == nsKey && errs[i].StructNamespace() == structNsKey { found = true fe = errs[i] break } } EqualSkip(t, 2, found, true) NotEqualSkip(t, 2, fe, nil) EqualSkip(t, 2, fe.Field(), field) EqualSkip(t, 2, fe.StructField(), structField) EqualSkip(t, 2, fe.Tag(), expectedTag) } func AssertDeepError(t *testing.T, err error, nsKey, structNsKey, field, structField, expectedTag, actualTag string) { errs := err.(ValidationErrors) found := false var fe FieldError for i := 0; i < len(errs); i++ { if errs[i].Namespace() == nsKey && errs[i].StructNamespace() == structNsKey && errs[i].Tag() == expectedTag && errs[i].ActualTag() == actualTag { found = true fe = errs[i] break } } EqualSkip(t, 2, found, true) NotEqualSkip(t, 2, fe, nil) EqualSkip(t, 2, fe.Field(), field) EqualSkip(t, 2, fe.StructField(), structField) } func getError(err error, nsKey, structNsKey string) FieldError { errs := err.(ValidationErrors) var fe FieldError for i := 0; i < len(errs); i++ { if errs[i].Namespace() == nsKey && errs[i].StructNamespace() == structNsKey { fe = errs[i] break } } return fe } type valuer struct { Name string } func (v valuer) Value() (driver.Value, error) { if v.Name == "errorme" { panic("SQL Driver Valuer error: some kind of error") // return nil, errors.New("some kind of error") } if len(v.Name) == 0 { return nil, nil } return v.Name, nil } type MadeUpCustomType struct { FirstName string LastName string } func ValidateCustomType(field reflect.Value) interface{} { if cust, ok := field.Interface().(MadeUpCustomType); ok { if len(cust.FirstName) == 0 || len(cust.LastName) == 0 { return "" } return cust.FirstName + " " + cust.LastName } return "" } func OverrideIntTypeForSomeReason(field reflect.Value) interface{} { if i, ok := field.Interface().(int); ok { if i == 1 { return "1" } if i == 2 { return "12" } } return "" } type CustomMadeUpStruct struct { MadeUp MadeUpCustomType `validate:"required"` OverriddenInt int `validate:"gt=1"` } func ValidateValuerType(field reflect.Value) interface{} { if valuer, ok := field.Interface().(driver.Valuer); ok { val, err := valuer.Value() if err != nil { // handle the error how you want return nil } return val } return nil } type TestPartial struct { NoTag string BlankTag string `validate:""` Required string `validate:"required"` SubSlice []*SubTest `validate:"required,dive"` Sub *SubTest SubIgnore *SubTest `validate:"-"` Anonymous struct { A string `validate:"required"` ASubSlice []*SubTest `validate:"required,dive"` SubAnonStruct []struct { Test string `validate:"required"` OtherTest string `validate:"required"` } `validate:"required,dive"` } } type TestStruct struct { String string `validate:"required" json:"StringVal"` } func StructValidationTestStructSuccess(sl StructLevel) { st := sl.Current().Interface().(TestStruct) if st.String != "good value" { sl.ReportError(st.String, "StringVal", "String", "badvalueteststruct", "good value") } } func StructValidationTestStruct(sl StructLevel) { st := sl.Current().Interface().(TestStruct) if st.String != "bad value" { sl.ReportError(st.String, "StringVal", "String", "badvalueteststruct", "bad value") } } func StructValidationNoTestStructCustomName(sl StructLevel) { st := sl.Current().Interface().(TestStruct) if st.String != "bad value" { sl.ReportError(st.String, "String", "", "badvalueteststruct", "bad value") } } func StructValidationTestStructInvalid(sl StructLevel) { st := sl.Current().Interface().(TestStruct) if st.String != "bad value" { sl.ReportError(nil, "StringVal", "String", "badvalueteststruct", "bad value") } } func StructValidationTestStructReturnValidationErrors(sl StructLevel) { s := sl.Current().Interface().(TestStructReturnValidationErrors) errs := sl.Validator().Struct(s.Inner1.Inner2) if errs == nil { return } sl.ReportValidationErrors("Inner1.", "Inner1.", errs.(ValidationErrors)) } func StructValidationTestStructReturnValidationErrors2(sl StructLevel) { s := sl.Current().Interface().(TestStructReturnValidationErrors) errs := sl.Validator().Struct(s.Inner1.Inner2) if errs == nil { return } sl.ReportValidationErrors("Inner1JSON.", "Inner1.", errs.(ValidationErrors)) } type TestStructReturnValidationErrorsInner2 struct { String string `validate:"required" json:"JSONString"` } type TestStructReturnValidationErrorsInner1 struct { Inner2 *TestStructReturnValidationErrorsInner2 } type TestStructReturnValidationErrors struct { Inner1 *TestStructReturnValidationErrorsInner1 `json:"Inner1JSON"` } type StructLevelInvalidErr struct { Value string } func StructLevelInvalidError(sl StructLevel) { top := sl.Top().Interface().(StructLevelInvalidErr) s := sl.Current().Interface().(StructLevelInvalidErr) if top.Value == s.Value { sl.ReportError(nil, "Value", "Value", "required", "") } } func stringPtr(v string) *string { return &v } func intPtr(v int) *int { return &v } func float64Ptr(v float64) *float64 { return &v } func TestStructLevelInvalidError(t *testing.T) { validate := New() validate.RegisterStructValidation(StructLevelInvalidError, StructLevelInvalidErr{}) var test StructLevelInvalidErr err := validate.Struct(test) NotEqual(t, err, nil) errs, ok := err.(ValidationErrors) Equal(t, ok, true) fe := errs[0] Equal(t, fe.Field(), "Value") Equal(t, fe.StructField(), "Value") Equal(t, fe.Namespace(), "StructLevelInvalidErr.Value") Equal(t, fe.StructNamespace(), "StructLevelInvalidErr.Value") Equal(t, fe.Tag(), "required") Equal(t, fe.ActualTag(), "required") Equal(t, fe.Kind(), reflect.Invalid) Equal(t, fe.Type(), reflect.TypeOf(nil)) } func TestNameNamespace(t *testing.T) { type Inner2Namespace struct { String []string `validate:"dive,required" json:"JSONString"` } type Inner1Namespace struct { Inner2 *Inner2Namespace `json:"Inner2JSON"` } type Namespace struct { Inner1 *Inner1Namespace `json:"Inner1JSON"` } validate := New() validate.RegisterTagNameFunc(func(fld reflect.StructField) string { name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] if name == "-" { return "" } return name }) i2 := &Inner2Namespace{String: []string{"ok", "ok", "ok"}} i1 := &Inner1Namespace{Inner2: i2} ns := &Namespace{Inner1: i1} errs := validate.Struct(ns) Equal(t, errs, nil) i2.String[1] = "" errs = validate.Struct(ns) NotEqual(t, errs, nil) ve := errs.(ValidationErrors) Equal(t, len(ve), 1) AssertError(t, errs, "Namespace.Inner1JSON.Inner2JSON.JSONString[1]", "Namespace.Inner1.Inner2.String[1]", "JSONString[1]", "String[1]", "required") fe := getError(ve, "Namespace.Inner1JSON.Inner2JSON.JSONString[1]", "Namespace.Inner1.Inner2.String[1]") NotEqual(t, fe, nil) Equal(t, fe.Field(), "JSONString[1]") Equal(t, fe.StructField(), "String[1]") Equal(t, fe.Namespace(), "Namespace.Inner1JSON.Inner2JSON.JSONString[1]") Equal(t, fe.StructNamespace(), "Namespace.Inner1.Inner2.String[1]") } func TestAnonymous(t *testing.T) { validate := New() validate.RegisterTagNameFunc(func(fld reflect.StructField) string { name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] if name == "-" { return "" } return name }) type Test struct { Anonymous struct { A string `validate:"required" json:"EH"` } AnonymousB struct { B string `validate:"required" json:"BEE"` } anonymousC struct { c string `validate:"required"` } } tst := &Test{ Anonymous: struct { A string `validate:"required" json:"EH"` }{ A: "1", }, AnonymousB: struct { B string `validate:"required" json:"BEE"` }{ B: "", }, anonymousC: struct { c string `validate:"required"` }{ c: "", }, } Equal(t, tst.anonymousC.c, "") err := validate.Struct(tst) NotEqual(t, err, nil) errs := err.(ValidationErrors) Equal(t, len(errs), 1) AssertError(t, errs, "Test.AnonymousB.BEE", "Test.AnonymousB.B", "BEE", "B", "required") fe := getError(errs, "Test.AnonymousB.BEE", "Test.AnonymousB.B") NotEqual(t, fe, nil) Equal(t, fe.Field(), "BEE") Equal(t, fe.StructField(), "B") s := struct { c string `validate:"required"` }{ c: "", } err = validate.Struct(s) Equal(t, err, nil) } func TestAnonymousSameStructDifferentTags(t *testing.T) { validate := New() validate.RegisterTagNameFunc(func(fld reflect.StructField) string { name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] if name == "-" { return "" } return name }) type Test struct { A interface{} } tst := &Test{ A: struct { A string `validate:"required"` }{ A: "", }, } err := validate.Struct(tst) NotEqual(t, err, nil) errs := err.(ValidationErrors) Equal(t, len(errs), 1) AssertError(t, errs, "Test.A.A", "Test.A.A", "A", "A", "required") tst = &Test{ A: struct { A string `validate:"omitempty,required"` }{ A: "", }, } err = validate.Struct(tst) Equal(t, err, nil) } func TestStructLevelReturnValidationErrors(t *testing.T) { validate := New() validate.RegisterStructValidation(StructValidationTestStructReturnValidationErrors, TestStructReturnValidationErrors{}) inner2 := &TestStructReturnValidationErrorsInner2{ String: "I'm HERE", } inner1 := &TestStructReturnValidationErrorsInner1{ Inner2: inner2, } val := &TestStructReturnValidationErrors{ Inner1: inner1, } errs := validate.Struct(val) Equal(t, errs, nil) inner2.String = "" errs = validate.Struct(val) NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 2) AssertError(t, errs, "TestStructReturnValidationErrors.Inner1.Inner2.String", "TestStructReturnValidationErrors.Inner1.Inner2.String", "String", "String", "required") // this is an extra error reported from struct validation AssertError(t, errs, "TestStructReturnValidationErrors.Inner1.TestStructReturnValidationErrorsInner2.String", "TestStructReturnValidationErrors.Inner1.TestStructReturnValidationErrorsInner2.String", "String", "String", "required") } func TestStructLevelReturnValidationErrorsWithJSON(t *testing.T) { validate := New() validate.RegisterTagNameFunc(func(fld reflect.StructField) string { name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] if name == "-" { return "" } return name }) validate.RegisterStructValidation(StructValidationTestStructReturnValidationErrors2, TestStructReturnValidationErrors{}) inner2 := &TestStructReturnValidationErrorsInner2{ String: "I'm HERE", } inner1 := &TestStructReturnValidationErrorsInner1{ Inner2: inner2, } val := &TestStructReturnValidationErrors{ Inner1: inner1, } errs := validate.Struct(val) Equal(t, errs, nil) inner2.String = "" errs = validate.Struct(val) NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 2) AssertError(t, errs, "TestStructReturnValidationErrors.Inner1JSON.Inner2.JSONString", "TestStructReturnValidationErrors.Inner1.Inner2.String", "JSONString", "String", "required") // this is an extra error reported from struct validation, it's a badly formatted one, but on purpose AssertError(t, errs, "TestStructReturnValidationErrors.Inner1JSON.TestStructReturnValidationErrorsInner2.JSONString", "TestStructReturnValidationErrors.Inner1.TestStructReturnValidationErrorsInner2.String", "JSONString", "String", "required") fe := getError(errs, "TestStructReturnValidationErrors.Inner1JSON.Inner2.JSONString", "TestStructReturnValidationErrors.Inner1.Inner2.String") NotEqual(t, fe, nil) // check for proper JSON namespace Equal(t, fe.Field(), "JSONString") Equal(t, fe.StructField(), "String") Equal(t, fe.Namespace(), "TestStructReturnValidationErrors.Inner1JSON.Inner2.JSONString") Equal(t, fe.StructNamespace(), "TestStructReturnValidationErrors.Inner1.Inner2.String") fe = getError(errs, "TestStructReturnValidationErrors.Inner1JSON.TestStructReturnValidationErrorsInner2.JSONString", "TestStructReturnValidationErrors.Inner1.TestStructReturnValidationErrorsInner2.String") NotEqual(t, fe, nil) // check for proper JSON namespace Equal(t, fe.Field(), "JSONString") Equal(t, fe.StructField(), "String") Equal(t, fe.Namespace(), "TestStructReturnValidationErrors.Inner1JSON.TestStructReturnValidationErrorsInner2.JSONString") Equal(t, fe.StructNamespace(), "TestStructReturnValidationErrors.Inner1.TestStructReturnValidationErrorsInner2.String") } func TestStructLevelValidations(t *testing.T) { v1 := New() v1.RegisterStructValidation(StructValidationTestStruct, TestStruct{}) tst := &TestStruct{ String: "good value", } errs := v1.Struct(tst) NotEqual(t, errs, nil) AssertError(t, errs, "TestStruct.StringVal", "TestStruct.String", "StringVal", "String", "badvalueteststruct") v2 := New() v2.RegisterStructValidation(StructValidationNoTestStructCustomName, TestStruct{}) errs = v2.Struct(tst) NotEqual(t, errs, nil) AssertError(t, errs, "TestStruct.String", "TestStruct.String", "String", "String", "badvalueteststruct") v3 := New() v3.RegisterStructValidation(StructValidationTestStructInvalid, TestStruct{}) errs = v3.Struct(tst) NotEqual(t, errs, nil) AssertError(t, errs, "TestStruct.StringVal", "TestStruct.String", "StringVal", "String", "badvalueteststruct") v4 := New() v4.RegisterStructValidation(StructValidationTestStructSuccess, TestStruct{}) errs = v4.Struct(tst) Equal(t, errs, nil) } func TestAliasTags(t *testing.T) { validate := New() validate.RegisterAlias("iscoloralias", "hexcolor|rgb|rgba|hsl|hsla") s := "rgb(255,255,255)" errs := validate.Var(s, "iscoloralias") Equal(t, errs, nil) s = "" errs = validate.Var(s, "omitempty,iscoloralias") Equal(t, errs, nil) s = "rgb(255,255,0)" errs = validate.Var(s, "iscoloralias,len=5") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "len") type Test struct { Color string `validate:"iscoloralias"` } tst := &Test{ Color: "#000", } errs = validate.Struct(tst) Equal(t, errs, nil) tst.Color = "cfvre" errs = validate.Struct(tst) NotEqual(t, errs, nil) AssertError(t, errs, "Test.Color", "Test.Color", "Color", "Color", "iscoloralias") fe := getError(errs, "Test.Color", "Test.Color") NotEqual(t, fe, nil) Equal(t, fe.ActualTag(), "hexcolor|rgb|rgba|hsl|hsla") validate.RegisterAlias("req", "required,dive,iscoloralias") arr := []string{"val1", "#fff", "#000"} errs = validate.Var(arr, "req") NotEqual(t, errs, nil) AssertError(t, errs, "[0]", "[0]", "[0]", "[0]", "iscoloralias") PanicMatches(t, func() { validate.RegisterAlias("exists!", "gt=5,lt=10") }, "Alias 'exists!' either contains restricted characters or is the same as a restricted tag needed for normal operation") } func TestNilValidator(t *testing.T) { type TestStruct struct { Test string `validate:"required"` } ts := TestStruct{} var val *Validate fn := func(fl FieldLevel) bool { return fl.Parent().String() == fl.Field().String() } PanicMatches(t, func() { val.RegisterCustomTypeFunc(ValidateCustomType, MadeUpCustomType{}) }, "runtime error: invalid memory address or nil pointer dereference") PanicMatches(t, func() { _ = val.RegisterValidation("something", fn) }, "runtime error: invalid memory address or nil pointer dereference") PanicMatches(t, func() { _ = val.Var(ts.Test, "required") }, "runtime error: invalid memory address or nil pointer dereference") PanicMatches(t, func() { _ = val.VarWithValue("test", ts.Test, "required") }, "runtime error: invalid memory address or nil pointer dereference") PanicMatches(t, func() { _ = val.Struct(ts) }, "runtime error: invalid memory address or nil pointer dereference") PanicMatches(t, func() { _ = val.StructExcept(ts, "Test") }, "runtime error: invalid memory address or nil pointer dereference") PanicMatches(t, func() { _ = val.StructPartial(ts, "Test") }, "runtime error: invalid memory address or nil pointer dereference") } func TestStructPartial(t *testing.T) { p1 := []string{ "NoTag", "Required", } p2 := []string{ "SubSlice[0].Test", "Sub", "SubIgnore", "Anonymous.A", } p3 := []string{ "SubTest.Test", } p4 := []string{ "A", } tPartial := &TestPartial{ NoTag: "NoTag", Required: "Required", SubSlice: []*SubTest{ { Test: "Required", }, { Test: "Required", }, }, Sub: &SubTest{ Test: "1", }, SubIgnore: &SubTest{ Test: "", }, Anonymous: struct { A string `validate:"required"` ASubSlice []*SubTest `validate:"required,dive"` SubAnonStruct []struct { Test string `validate:"required"` OtherTest string `validate:"required"` } `validate:"required,dive"` }{ A: "1", ASubSlice: []*SubTest{ { Test: "Required", }, { Test: "Required", }, }, SubAnonStruct: []struct { Test string `validate:"required"` OtherTest string `validate:"required"` }{ {"Required", "RequiredOther"}, {"Required", "RequiredOther"}, }, }, } validate := New() // the following should all return no errors as everything is valid in // the default state errs := validate.StructPartialCtx(context.Background(), tPartial, p1...) Equal(t, errs, nil) errs = validate.StructPartial(tPartial, p2...) Equal(t, errs, nil) // this isn't really a robust test, but is ment to illustrate the ANON CASE below errs = validate.StructPartial(tPartial.SubSlice[0], p3...) Equal(t, errs, nil) errs = validate.StructExceptCtx(context.Background(), tPartial, p1...) Equal(t, errs, nil) errs = validate.StructExcept(tPartial, p2...) Equal(t, errs, nil) // mod tParial for required feild and re-test making sure invalid fields are NOT required: tPartial.Required = "" errs = validate.StructExcept(tPartial, p1...) Equal(t, errs, nil) errs = validate.StructPartial(tPartial, p2...) Equal(t, errs, nil) // inversion and retesting Partial to generate failures: errs = validate.StructPartial(tPartial, p1...) NotEqual(t, errs, nil) AssertError(t, errs, "TestPartial.Required", "TestPartial.Required", "Required", "Required", "required") errs = validate.StructExcept(tPartial, p2...) AssertError(t, errs, "TestPartial.Required", "TestPartial.Required", "Required", "Required", "required") // reset Required field, and set nested struct tPartial.Required = "Required" tPartial.Anonymous.A = "" // will pass as unset feilds is not going to be tested errs = validate.StructPartial(tPartial, p1...) Equal(t, errs, nil) errs = validate.StructExcept(tPartial, p2...) Equal(t, errs, nil) // ANON CASE the response here is strange, it clearly does what it is being told to errs = validate.StructExcept(tPartial.Anonymous, p4...) Equal(t, errs, nil) // will fail as unset feild is tested errs = validate.StructPartial(tPartial, p2...) NotEqual(t, errs, nil) AssertError(t, errs, "TestPartial.Anonymous.A", "TestPartial.Anonymous.A", "A", "A", "required") errs = validate.StructExcept(tPartial, p1...) NotEqual(t, errs, nil) AssertError(t, errs, "TestPartial.Anonymous.A", "TestPartial.Anonymous.A", "A", "A", "required") // reset nested struct and unset struct in slice tPartial.Anonymous.A = "Required" tPartial.SubSlice[0].Test = "" // these will pass as unset item is NOT tested errs = validate.StructPartial(tPartial, p1...) Equal(t, errs, nil) errs = validate.StructExcept(tPartial, p2...) Equal(t, errs, nil) // these will fail as unset item IS tested errs = validate.StructExcept(tPartial, p1...) AssertError(t, errs, "TestPartial.SubSlice[0].Test", "TestPartial.SubSlice[0].Test", "Test", "Test", "required") Equal(t, len(errs.(ValidationErrors)), 1) errs = validate.StructPartial(tPartial, p2...) NotEqual(t, errs, nil) AssertError(t, errs, "TestPartial.SubSlice[0].Test", "TestPartial.SubSlice[0].Test", "Test", "Test", "required") Equal(t, len(errs.(ValidationErrors)), 1) // Unset second slice member concurrently to test dive behavior: tPartial.SubSlice[1].Test = "" errs = validate.StructPartial(tPartial, p1...) Equal(t, errs, nil) // NOTE: When specifying nested items, it is still the users responsibility // to specify the dive tag, the library does not override this. errs = validate.StructExcept(tPartial, p2...) NotEqual(t, errs, nil) AssertError(t, errs, "TestPartial.SubSlice[1].Test", "TestPartial.SubSlice[1].Test", "Test", "Test", "required") errs = validate.StructExcept(tPartial, p1...) Equal(t, len(errs.(ValidationErrors)), 2) AssertError(t, errs, "TestPartial.SubSlice[0].Test", "TestPartial.SubSlice[0].Test", "Test", "Test", "required") AssertError(t, errs, "TestPartial.SubSlice[1].Test", "TestPartial.SubSlice[1].Test", "Test", "Test", "required") errs = validate.StructPartial(tPartial, p2...) NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 1) AssertError(t, errs, "TestPartial.SubSlice[0].Test", "TestPartial.SubSlice[0].Test", "Test", "Test", "required") // reset struct in slice, and unset struct in slice in unset posistion tPartial.SubSlice[0].Test = "Required" // these will pass as the unset item is NOT tested errs = validate.StructPartial(tPartial, p1...) Equal(t, errs, nil) errs = validate.StructPartial(tPartial, p2...) Equal(t, errs, nil) // testing for missing item by exception, yes it dives and fails errs = validate.StructExcept(tPartial, p1...) NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 1) AssertError(t, errs, "TestPartial.SubSlice[1].Test", "TestPartial.SubSlice[1].Test", "Test", "Test", "required") errs = validate.StructExcept(tPartial, p2...) NotEqual(t, errs, nil) AssertError(t, errs, "TestPartial.SubSlice[1].Test", "TestPartial.SubSlice[1].Test", "Test", "Test", "required") tPartial.SubSlice[1].Test = "Required" tPartial.Anonymous.SubAnonStruct[0].Test = "" // these will pass as the unset item is NOT tested errs = validate.StructPartial(tPartial, p1...) Equal(t, errs, nil) errs = validate.StructPartial(tPartial, p2...) Equal(t, errs, nil) errs = validate.StructExcept(tPartial, p1...) NotEqual(t, errs, nil) AssertError(t, errs, "TestPartial.Anonymous.SubAnonStruct[0].Test", "TestPartial.Anonymous.SubAnonStruct[0].Test", "Test", "Test", "required") errs = validate.StructExcept(tPartial, p2...) NotEqual(t, errs, nil) AssertError(t, errs, "TestPartial.Anonymous.SubAnonStruct[0].Test", "TestPartial.Anonymous.SubAnonStruct[0].Test", "Test", "Test", "required") } func TestCrossStructLteFieldValidation(t *testing.T) { var errs error validate := New() type Inner struct { CreatedAt *time.Time String string Int int Uint uint Float float64 Array []string } type Test struct { Inner *Inner CreatedAt *time.Time `validate:"ltecsfield=Inner.CreatedAt"` String string `validate:"ltecsfield=Inner.String"` Int int `validate:"ltecsfield=Inner.Int"` Uint uint `validate:"ltecsfield=Inner.Uint"` Float float64 `validate:"ltecsfield=Inner.Float"` Array []string `validate:"ltecsfield=Inner.Array"` } now := time.Now().UTC() then := now.Add(time.Hour * 5) inner := &Inner{ CreatedAt: &then, String: "abcd", Int: 13, Uint: 13, Float: 1.13, Array: []string{"val1", "val2"}, } test := &Test{ Inner: inner, CreatedAt: &now, String: "abc", Int: 12, Uint: 12, Float: 1.12, Array: []string{"val1"}, } errs = validate.Struct(test) Equal(t, errs, nil) test.CreatedAt = &then test.String = "abcd" test.Int = 13 test.Uint = 13 test.Float = 1.13 test.Array = []string{"val1", "val2"} errs = validate.Struct(test) Equal(t, errs, nil) after := now.Add(time.Hour * 10) test.CreatedAt = &after test.String = "abce" test.Int = 14 test.Uint = 14 test.Float = 1.14 test.Array = []string{"val1", "val2", "val3"} errs = validate.Struct(test) NotEqual(t, errs, nil) AssertError(t, errs, "Test.CreatedAt", "Test.CreatedAt", "CreatedAt", "CreatedAt", "ltecsfield") AssertError(t, errs, "Test.String", "Test.String", "String", "String", "ltecsfield") AssertError(t, errs, "Test.Int", "Test.Int", "Int", "Int", "ltecsfield") AssertError(t, errs, "Test.Uint", "Test.Uint", "Uint", "Uint", "ltecsfield") AssertError(t, errs, "Test.Float", "Test.Float", "Float", "Float", "ltecsfield") AssertError(t, errs, "Test.Array", "Test.Array", "Array", "Array", "ltecsfield") errs = validate.VarWithValueCtx(context.Background(), 1, "", "ltecsfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "ltecsfield") // this test is for the WARNING about unforeseen validation issues. errs = validate.VarWithValue(test, now, "ltecsfield") NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 6) AssertError(t, errs, "Test.CreatedAt", "Test.CreatedAt", "CreatedAt", "CreatedAt", "ltecsfield") AssertError(t, errs, "Test.String", "Test.String", "String", "String", "ltecsfield") AssertError(t, errs, "Test.Int", "Test.Int", "Int", "Int", "ltecsfield") AssertError(t, errs, "Test.Uint", "Test.Uint", "Uint", "Uint", "ltecsfield") AssertError(t, errs, "Test.Float", "Test.Float", "Float", "Float", "ltecsfield") AssertError(t, errs, "Test.Array", "Test.Array", "Array", "Array", "ltecsfield") type Other struct { Value string } type Test2 struct { Value Other Time time.Time `validate:"ltecsfield=Value"` } tst := Test2{ Value: Other{Value: "StringVal"}, Time: then, } errs = validate.Struct(tst) NotEqual(t, errs, nil) AssertError(t, errs, "Test2.Time", "Test2.Time", "Time", "Time", "ltecsfield") // Tests for time.Duration type. // -- Validations for variables of time.Duration type. errs = validate.VarWithValue(time.Hour, time.Hour+time.Minute, "ltecsfield") Equal(t, errs, nil) errs = validate.VarWithValue(time.Hour, time.Hour, "ltecsfield") Equal(t, errs, nil) errs = validate.VarWithValue(time.Hour, time.Hour-time.Minute, "ltecsfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "ltecsfield") errs = validate.VarWithValue(time.Duration(0), -time.Minute, "omitempty,ltecsfield") Equal(t, errs, nil) // -- Validations for a struct and an inner struct with time.Duration type fields. type TimeDurationInner struct { Duration time.Duration } var timeDurationInner *TimeDurationInner type TimeDurationTest struct { Inner *TimeDurationInner Duration time.Duration `validate:"ltecsfield=Inner.Duration"` } var timeDurationTest *TimeDurationTest timeDurationInner = &TimeDurationInner{time.Hour + time.Minute} timeDurationTest = &TimeDurationTest{timeDurationInner, time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) timeDurationInner = &TimeDurationInner{time.Hour} timeDurationTest = &TimeDurationTest{timeDurationInner, time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) timeDurationInner = &TimeDurationInner{time.Hour - time.Minute} timeDurationTest = &TimeDurationTest{timeDurationInner, time.Hour} errs = validate.Struct(timeDurationTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeDurationTest.Duration", "TimeDurationTest.Duration", "Duration", "Duration", "ltecsfield") type TimeDurationOmitemptyTest struct { Inner *TimeDurationInner Duration time.Duration `validate:"omitempty,ltecsfield=Inner.Duration"` } var timeDurationOmitemptyTest *TimeDurationOmitemptyTest timeDurationInner = &TimeDurationInner{-time.Minute} timeDurationOmitemptyTest = &TimeDurationOmitemptyTest{timeDurationInner, time.Duration(0)} errs = validate.Struct(timeDurationOmitemptyTest) Equal(t, errs, nil) } func TestCrossStructLtFieldValidation(t *testing.T) { var errs error validate := New() type Inner struct { CreatedAt *time.Time String string Int int Uint uint Float float64 Array []string } type Test struct { Inner *Inner CreatedAt *time.Time `validate:"ltcsfield=Inner.CreatedAt"` String string `validate:"ltcsfield=Inner.String"` Int int `validate:"ltcsfield=Inner.Int"` Uint uint `validate:"ltcsfield=Inner.Uint"` Float float64 `validate:"ltcsfield=Inner.Float"` Array []string `validate:"ltcsfield=Inner.Array"` } now := time.Now().UTC() then := now.Add(time.Hour * 5) inner := &Inner{ CreatedAt: &then, String: "abcd", Int: 13, Uint: 13, Float: 1.13, Array: []string{"val1", "val2"}, } test := &Test{ Inner: inner, CreatedAt: &now, String: "abc", Int: 12, Uint: 12, Float: 1.12, Array: []string{"val1"}, } errs = validate.Struct(test) Equal(t, errs, nil) test.CreatedAt = &then test.String = "abcd" test.Int = 13 test.Uint = 13 test.Float = 1.13 test.Array = []string{"val1", "val2"} errs = validate.Struct(test) NotEqual(t, errs, nil) AssertError(t, errs, "Test.CreatedAt", "Test.CreatedAt", "CreatedAt", "CreatedAt", "ltcsfield") AssertError(t, errs, "Test.String", "Test.String", "String", "String", "ltcsfield") AssertError(t, errs, "Test.Int", "Test.Int", "Int", "Int", "ltcsfield") AssertError(t, errs, "Test.Uint", "Test.Uint", "Uint", "Uint", "ltcsfield") AssertError(t, errs, "Test.Float", "Test.Float", "Float", "Float", "ltcsfield") AssertError(t, errs, "Test.Array", "Test.Array", "Array", "Array", "ltcsfield") errs = validate.VarWithValue(1, "", "ltcsfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "ltcsfield") // this test is for the WARNING about unforeseen validation issues. errs = validate.VarWithValue(test, now, "ltcsfield") NotEqual(t, errs, nil) AssertError(t, errs, "Test.CreatedAt", "Test.CreatedAt", "CreatedAt", "CreatedAt", "ltcsfield") AssertError(t, errs, "Test.String", "Test.String", "String", "String", "ltcsfield") AssertError(t, errs, "Test.Int", "Test.Int", "Int", "Int", "ltcsfield") AssertError(t, errs, "Test.Uint", "Test.Uint", "Uint", "Uint", "ltcsfield") AssertError(t, errs, "Test.Float", "Test.Float", "Float", "Float", "ltcsfield") AssertError(t, errs, "Test.Array", "Test.Array", "Array", "Array", "ltcsfield") type Other struct { Value string } type Test2 struct { Value Other Time time.Time `validate:"ltcsfield=Value"` } tst := Test2{ Value: Other{Value: "StringVal"}, Time: then, } errs = validate.Struct(tst) NotEqual(t, errs, nil) AssertError(t, errs, "Test2.Time", "Test2.Time", "Time", "Time", "ltcsfield") // Tests for time.Duration type. // -- Validations for variables of time.Duration type. errs = validate.VarWithValue(time.Hour, time.Hour+time.Minute, "ltcsfield") Equal(t, errs, nil) errs = validate.VarWithValue(time.Hour, time.Hour, "ltcsfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "ltcsfield") errs = validate.VarWithValue(time.Hour, time.Hour-time.Minute, "ltcsfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "ltcsfield") errs = validate.VarWithValue(time.Duration(0), -time.Minute, "omitempty,ltcsfield") Equal(t, errs, nil) // -- Validations for a struct and an inner struct with time.Duration type fields. type TimeDurationInner struct { Duration time.Duration } var timeDurationInner *TimeDurationInner type TimeDurationTest struct { Inner *TimeDurationInner Duration time.Duration `validate:"ltcsfield=Inner.Duration"` } var timeDurationTest *TimeDurationTest timeDurationInner = &TimeDurationInner{time.Hour + time.Minute} timeDurationTest = &TimeDurationTest{timeDurationInner, time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) timeDurationInner = &TimeDurationInner{time.Hour} timeDurationTest = &TimeDurationTest{timeDurationInner, time.Hour} errs = validate.Struct(timeDurationTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeDurationTest.Duration", "TimeDurationTest.Duration", "Duration", "Duration", "ltcsfield") timeDurationInner = &TimeDurationInner{time.Hour - time.Minute} timeDurationTest = &TimeDurationTest{timeDurationInner, time.Hour} errs = validate.Struct(timeDurationTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeDurationTest.Duration", "TimeDurationTest.Duration", "Duration", "Duration", "ltcsfield") type TimeDurationOmitemptyTest struct { Inner *TimeDurationInner Duration time.Duration `validate:"omitempty,ltcsfield=Inner.Duration"` } var timeDurationOmitemptyTest *TimeDurationOmitemptyTest timeDurationInner = &TimeDurationInner{-time.Minute} timeDurationOmitemptyTest = &TimeDurationOmitemptyTest{timeDurationInner, time.Duration(0)} errs = validate.Struct(timeDurationOmitemptyTest) Equal(t, errs, nil) } func TestCrossStructGteFieldValidation(t *testing.T) { var errs error validate := New() type Inner struct { CreatedAt *time.Time String string Int int Uint uint Float float64 Array []string } type Test struct { Inner *Inner CreatedAt *time.Time `validate:"gtecsfield=Inner.CreatedAt"` String string `validate:"gtecsfield=Inner.String"` Int int `validate:"gtecsfield=Inner.Int"` Uint uint `validate:"gtecsfield=Inner.Uint"` Float float64 `validate:"gtecsfield=Inner.Float"` Array []string `validate:"gtecsfield=Inner.Array"` } now := time.Now().UTC() then := now.Add(time.Hour * -5) inner := &Inner{ CreatedAt: &then, String: "abcd", Int: 13, Uint: 13, Float: 1.13, Array: []string{"val1", "val2"}, } test := &Test{ Inner: inner, CreatedAt: &now, String: "abcde", Int: 14, Uint: 14, Float: 1.14, Array: []string{"val1", "val2", "val3"}, } errs = validate.Struct(test) Equal(t, errs, nil) test.CreatedAt = &then test.String = "abcd" test.Int = 13 test.Uint = 13 test.Float = 1.13 test.Array = []string{"val1", "val2"} errs = validate.Struct(test) Equal(t, errs, nil) before := now.Add(time.Hour * -10) test.CreatedAt = &before test.String = "abc" test.Int = 12 test.Uint = 12 test.Float = 1.12 test.Array = []string{"val1"} errs = validate.Struct(test) NotEqual(t, errs, nil) AssertError(t, errs, "Test.CreatedAt", "Test.CreatedAt", "CreatedAt", "CreatedAt", "gtecsfield") AssertError(t, errs, "Test.String", "Test.String", "String", "String", "gtecsfield") AssertError(t, errs, "Test.Int", "Test.Int", "Int", "Int", "gtecsfield") AssertError(t, errs, "Test.Uint", "Test.Uint", "Uint", "Uint", "gtecsfield") AssertError(t, errs, "Test.Float", "Test.Float", "Float", "Float", "gtecsfield") AssertError(t, errs, "Test.Array", "Test.Array", "Array", "Array", "gtecsfield") errs = validate.VarWithValue(1, "", "gtecsfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "gtecsfield") // this test is for the WARNING about unforeseen validation issues. errs = validate.VarWithValue(test, now, "gtecsfield") NotEqual(t, errs, nil) AssertError(t, errs, "Test.CreatedAt", "Test.CreatedAt", "CreatedAt", "CreatedAt", "gtecsfield") AssertError(t, errs, "Test.String", "Test.String", "String", "String", "gtecsfield") AssertError(t, errs, "Test.Int", "Test.Int", "Int", "Int", "gtecsfield") AssertError(t, errs, "Test.Uint", "Test.Uint", "Uint", "Uint", "gtecsfield") AssertError(t, errs, "Test.Float", "Test.Float", "Float", "Float", "gtecsfield") AssertError(t, errs, "Test.Array", "Test.Array", "Array", "Array", "gtecsfield") type Other struct { Value string } type Test2 struct { Value Other Time time.Time `validate:"gtecsfield=Value"` } tst := Test2{ Value: Other{Value: "StringVal"}, Time: then, } errs = validate.Struct(tst) NotEqual(t, errs, nil) AssertError(t, errs, "Test2.Time", "Test2.Time", "Time", "Time", "gtecsfield") // Tests for time.Duration type. // -- Validations for variables of time.Duration type. errs = validate.VarWithValue(time.Hour, time.Hour-time.Minute, "gtecsfield") Equal(t, errs, nil) errs = validate.VarWithValue(time.Hour, time.Hour, "gtecsfield") Equal(t, errs, nil) errs = validate.VarWithValue(time.Hour, time.Hour+time.Minute, "gtecsfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "gtecsfield") errs = validate.VarWithValue(time.Duration(0), time.Hour, "omitempty,gtecsfield") Equal(t, errs, nil) // -- Validations for a struct and an inner struct with time.Duration type fields. type TimeDurationInner struct { Duration time.Duration } var timeDurationInner *TimeDurationInner type TimeDurationTest struct { Inner *TimeDurationInner Duration time.Duration `validate:"gtecsfield=Inner.Duration"` } var timeDurationTest *TimeDurationTest timeDurationInner = &TimeDurationInner{time.Hour - time.Minute} timeDurationTest = &TimeDurationTest{timeDurationInner, time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) timeDurationInner = &TimeDurationInner{time.Hour} timeDurationTest = &TimeDurationTest{timeDurationInner, time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) timeDurationInner = &TimeDurationInner{time.Hour + time.Minute} timeDurationTest = &TimeDurationTest{timeDurationInner, time.Hour} errs = validate.Struct(timeDurationTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeDurationTest.Duration", "TimeDurationTest.Duration", "Duration", "Duration", "gtecsfield") type TimeDurationOmitemptyTest struct { Inner *TimeDurationInner Duration time.Duration `validate:"omitempty,gtecsfield=Inner.Duration"` } var timeDurationOmitemptyTest *TimeDurationOmitemptyTest timeDurationInner = &TimeDurationInner{time.Hour} timeDurationOmitemptyTest = &TimeDurationOmitemptyTest{timeDurationInner, time.Duration(0)} errs = validate.Struct(timeDurationOmitemptyTest) Equal(t, errs, nil) } func TestCrossStructGtFieldValidation(t *testing.T) { var errs error validate := New() type Inner struct { CreatedAt *time.Time String string Int int Uint uint Float float64 Array []string } type Test struct { Inner *Inner CreatedAt *time.Time `validate:"gtcsfield=Inner.CreatedAt"` String string `validate:"gtcsfield=Inner.String"` Int int `validate:"gtcsfield=Inner.Int"` Uint uint `validate:"gtcsfield=Inner.Uint"` Float float64 `validate:"gtcsfield=Inner.Float"` Array []string `validate:"gtcsfield=Inner.Array"` } now := time.Now().UTC() then := now.Add(time.Hour * -5) inner := &Inner{ CreatedAt: &then, String: "abcd", Int: 13, Uint: 13, Float: 1.13, Array: []string{"val1", "val2"}, } test := &Test{ Inner: inner, CreatedAt: &now, String: "abcde", Int: 14, Uint: 14, Float: 1.14, Array: []string{"val1", "val2", "val3"}, } errs = validate.Struct(test) Equal(t, errs, nil) test.CreatedAt = &then test.String = "abcd" test.Int = 13 test.Uint = 13 test.Float = 1.13 test.Array = []string{"val1", "val2"} errs = validate.Struct(test) NotEqual(t, errs, nil) AssertError(t, errs, "Test.CreatedAt", "Test.CreatedAt", "CreatedAt", "CreatedAt", "gtcsfield") AssertError(t, errs, "Test.String", "Test.String", "String", "String", "gtcsfield") AssertError(t, errs, "Test.Int", "Test.Int", "Int", "Int", "gtcsfield") AssertError(t, errs, "Test.Uint", "Test.Uint", "Uint", "Uint", "gtcsfield") AssertError(t, errs, "Test.Float", "Test.Float", "Float", "Float", "gtcsfield") AssertError(t, errs, "Test.Array", "Test.Array", "Array", "Array", "gtcsfield") errs = validate.VarWithValue(1, "", "gtcsfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "gtcsfield") // this test is for the WARNING about unforeseen validation issues. errs = validate.VarWithValue(test, now, "gtcsfield") NotEqual(t, errs, nil) AssertError(t, errs, "Test.CreatedAt", "Test.CreatedAt", "CreatedAt", "CreatedAt", "gtcsfield") AssertError(t, errs, "Test.String", "Test.String", "String", "String", "gtcsfield") AssertError(t, errs, "Test.Int", "Test.Int", "Int", "Int", "gtcsfield") AssertError(t, errs, "Test.Uint", "Test.Uint", "Uint", "Uint", "gtcsfield") AssertError(t, errs, "Test.Float", "Test.Float", "Float", "Float", "gtcsfield") AssertError(t, errs, "Test.Array", "Test.Array", "Array", "Array", "gtcsfield") type Other struct { Value string } type Test2 struct { Value Other Time time.Time `validate:"gtcsfield=Value"` } tst := Test2{ Value: Other{Value: "StringVal"}, Time: then, } errs = validate.Struct(tst) NotEqual(t, errs, nil) AssertError(t, errs, "Test2.Time", "Test2.Time", "Time", "Time", "gtcsfield") // Tests for time.Duration type. // -- Validations for variables of time.Duration type. errs = validate.VarWithValue(time.Hour, time.Hour-time.Minute, "gtcsfield") Equal(t, errs, nil) errs = validate.VarWithValue(time.Hour, time.Hour, "gtcsfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "gtcsfield") errs = validate.VarWithValue(time.Hour, time.Hour+time.Minute, "gtcsfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "gtcsfield") errs = validate.VarWithValue(time.Duration(0), time.Hour, "omitempty,gtcsfield") Equal(t, errs, nil) // -- Validations for a struct and an inner struct with time.Duration type fields. type TimeDurationInner struct { Duration time.Duration } var timeDurationInner *TimeDurationInner type TimeDurationTest struct { Inner *TimeDurationInner Duration time.Duration `validate:"gtcsfield=Inner.Duration"` } var timeDurationTest *TimeDurationTest timeDurationInner = &TimeDurationInner{time.Hour - time.Minute} timeDurationTest = &TimeDurationTest{timeDurationInner, time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) timeDurationInner = &TimeDurationInner{time.Hour} timeDurationTest = &TimeDurationTest{timeDurationInner, time.Hour} errs = validate.Struct(timeDurationTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeDurationTest.Duration", "TimeDurationTest.Duration", "Duration", "Duration", "gtcsfield") timeDurationInner = &TimeDurationInner{time.Hour + time.Minute} timeDurationTest = &TimeDurationTest{timeDurationInner, time.Hour} errs = validate.Struct(timeDurationTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeDurationTest.Duration", "TimeDurationTest.Duration", "Duration", "Duration", "gtcsfield") type TimeDurationOmitemptyTest struct { Inner *TimeDurationInner Duration time.Duration `validate:"omitempty,gtcsfield=Inner.Duration"` } var timeDurationOmitemptyTest *TimeDurationOmitemptyTest timeDurationInner = &TimeDurationInner{time.Hour} timeDurationOmitemptyTest = &TimeDurationOmitemptyTest{timeDurationInner, time.Duration(0)} errs = validate.Struct(timeDurationOmitemptyTest) Equal(t, errs, nil) } func TestCrossStructNeFieldValidation(t *testing.T) { var errs error validate := New() type Inner struct { CreatedAt *time.Time } type Test struct { Inner *Inner CreatedAt *time.Time `validate:"necsfield=Inner.CreatedAt"` } now := time.Now().UTC() then := now.Add(time.Hour * 5) inner := &Inner{ CreatedAt: &then, } test := &Test{ Inner: inner, CreatedAt: &now, } errs = validate.Struct(test) Equal(t, errs, nil) test.CreatedAt = &then errs = validate.Struct(test) NotEqual(t, errs, nil) AssertError(t, errs, "Test.CreatedAt", "Test.CreatedAt", "CreatedAt", "CreatedAt", "necsfield") var j uint64 var k float64 var j2 uint64 var k2 float64 s := "abcd" i := 1 j = 1 k = 1.543 arr := []string{"test"} s2 := "abcd" i2 := 1 j2 = 1 k2 = 1.543 arr2 := []string{"test"} arr3 := []string{"test", "test2"} now2 := now errs = validate.VarWithValue(s, s2, "necsfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "necsfield") errs = validate.VarWithValue(i2, i, "necsfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "necsfield") errs = validate.VarWithValue(j2, j, "necsfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "necsfield") errs = validate.VarWithValue(k2, k, "necsfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "necsfield") errs = validate.VarWithValue(arr2, arr, "necsfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "necsfield") errs = validate.VarWithValue(now2, now, "necsfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "necsfield") errs = validate.VarWithValue(arr3, arr, "necsfield") Equal(t, errs, nil) type SInner struct { Name string } type TStruct struct { Inner *SInner CreatedAt *time.Time `validate:"necsfield=Inner"` } sinner := &SInner{ Name: "NAME", } test2 := &TStruct{ Inner: sinner, CreatedAt: &now, } errs = validate.Struct(test2) Equal(t, errs, nil) test2.Inner = nil errs = validate.Struct(test2) Equal(t, errs, nil) errs = validate.VarWithValue(nil, 1, "necsfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "necsfield") // Tests for time.Duration type. // -- Validations for variables of time.Duration type. errs = validate.VarWithValue(time.Hour, time.Hour-time.Minute, "necsfield") Equal(t, errs, nil) errs = validate.VarWithValue(time.Hour, time.Hour+time.Minute, "necsfield") Equal(t, errs, nil) errs = validate.VarWithValue(time.Hour, time.Hour, "necsfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "necsfield") errs = validate.VarWithValue(time.Duration(0), time.Duration(0), "omitempty,necsfield") Equal(t, errs, nil) // -- Validations for a struct and an inner struct with time.Duration type fields. type TimeDurationInner struct { Duration time.Duration } var timeDurationInner *TimeDurationInner type TimeDurationTest struct { Inner *TimeDurationInner Duration time.Duration `validate:"necsfield=Inner.Duration"` } var timeDurationTest *TimeDurationTest timeDurationInner = &TimeDurationInner{time.Hour - time.Minute} timeDurationTest = &TimeDurationTest{timeDurationInner, time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) timeDurationInner = &TimeDurationInner{time.Hour + time.Minute} timeDurationTest = &TimeDurationTest{timeDurationInner, time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) timeDurationInner = &TimeDurationInner{time.Hour} timeDurationTest = &TimeDurationTest{timeDurationInner, time.Hour} errs = validate.Struct(timeDurationTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeDurationTest.Duration", "TimeDurationTest.Duration", "Duration", "Duration", "necsfield") type TimeDurationOmitemptyTest struct { Inner *TimeDurationInner Duration time.Duration `validate:"omitempty,necsfield=Inner.Duration"` } var timeDurationOmitemptyTest *TimeDurationOmitemptyTest timeDurationInner = &TimeDurationInner{time.Duration(0)} timeDurationOmitemptyTest = &TimeDurationOmitemptyTest{timeDurationInner, time.Duration(0)} errs = validate.Struct(timeDurationOmitemptyTest) Equal(t, errs, nil) } func TestCrossStructEqFieldValidation(t *testing.T) { var errs error validate := New() type Inner struct { CreatedAt *time.Time } type Test struct { Inner *Inner CreatedAt *time.Time `validate:"eqcsfield=Inner.CreatedAt"` } now := time.Now().UTC() inner := &Inner{ CreatedAt: &now, } test := &Test{ Inner: inner, CreatedAt: &now, } errs = validate.Struct(test) Equal(t, errs, nil) newTime := time.Now().UTC() test.CreatedAt = &newTime errs = validate.Struct(test) NotEqual(t, errs, nil) AssertError(t, errs, "Test.CreatedAt", "Test.CreatedAt", "CreatedAt", "CreatedAt", "eqcsfield") var j uint64 var k float64 s := "abcd" i := 1 j = 1 k = 1.543 arr := []string{"test"} var j2 uint64 var k2 float64 s2 := "abcd" i2 := 1 j2 = 1 k2 = 1.543 arr2 := []string{"test"} arr3 := []string{"test", "test2"} now2 := now errs = validate.VarWithValue(s, s2, "eqcsfield") Equal(t, errs, nil) errs = validate.VarWithValue(i2, i, "eqcsfield") Equal(t, errs, nil) errs = validate.VarWithValue(j2, j, "eqcsfield") Equal(t, errs, nil) errs = validate.VarWithValue(k2, k, "eqcsfield") Equal(t, errs, nil) errs = validate.VarWithValue(arr2, arr, "eqcsfield") Equal(t, errs, nil) errs = validate.VarWithValue(now2, now, "eqcsfield") Equal(t, errs, nil) errs = validate.VarWithValue(arr3, arr, "eqcsfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "eqcsfield") type SInner struct { Name string } type TStruct struct { Inner *SInner CreatedAt *time.Time `validate:"eqcsfield=Inner"` } sinner := &SInner{ Name: "NAME", } test2 := &TStruct{ Inner: sinner, CreatedAt: &now, } errs = validate.Struct(test2) NotEqual(t, errs, nil) AssertError(t, errs, "TStruct.CreatedAt", "TStruct.CreatedAt", "CreatedAt", "CreatedAt", "eqcsfield") test2.Inner = nil errs = validate.Struct(test2) NotEqual(t, errs, nil) AssertError(t, errs, "TStruct.CreatedAt", "TStruct.CreatedAt", "CreatedAt", "CreatedAt", "eqcsfield") errs = validate.VarWithValue(nil, 1, "eqcsfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "eqcsfield") // Tests for time.Duration type. // -- Validations for variables of time.Duration type. errs = validate.VarWithValue(time.Hour, time.Hour, "eqcsfield") Equal(t, errs, nil) errs = validate.VarWithValue(time.Hour, time.Hour-time.Minute, "eqcsfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "eqcsfield") errs = validate.VarWithValue(time.Hour, time.Hour+time.Minute, "eqcsfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "eqcsfield") errs = validate.VarWithValue(time.Duration(0), time.Hour, "omitempty,eqcsfield") Equal(t, errs, nil) // -- Validations for a struct and an inner struct with time.Duration type fields. type TimeDurationInner struct { Duration time.Duration } var timeDurationInner *TimeDurationInner type TimeDurationTest struct { Inner *TimeDurationInner Duration time.Duration `validate:"eqcsfield=Inner.Duration"` } var timeDurationTest *TimeDurationTest timeDurationInner = &TimeDurationInner{time.Hour} timeDurationTest = &TimeDurationTest{timeDurationInner, time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) timeDurationInner = &TimeDurationInner{time.Hour - time.Minute} timeDurationTest = &TimeDurationTest{timeDurationInner, time.Hour} errs = validate.Struct(timeDurationTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeDurationTest.Duration", "TimeDurationTest.Duration", "Duration", "Duration", "eqcsfield") timeDurationInner = &TimeDurationInner{time.Hour + time.Minute} timeDurationTest = &TimeDurationTest{timeDurationInner, time.Hour} errs = validate.Struct(timeDurationTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeDurationTest.Duration", "TimeDurationTest.Duration", "Duration", "Duration", "eqcsfield") type TimeDurationOmitemptyTest struct { Inner *TimeDurationInner Duration time.Duration `validate:"omitempty,eqcsfield=Inner.Duration"` } var timeDurationOmitemptyTest *TimeDurationOmitemptyTest timeDurationInner = &TimeDurationInner{time.Hour} timeDurationOmitemptyTest = &TimeDurationOmitemptyTest{timeDurationInner, time.Duration(0)} errs = validate.Struct(timeDurationOmitemptyTest) Equal(t, errs, nil) } func TestCrossNamespaceFieldValidation(t *testing.T) { type SliceStruct struct { Name string } type Inner struct { CreatedAt *time.Time Slice []string SliceStructs []*SliceStruct SliceSlice [][]string SliceSliceStruct [][]*SliceStruct SliceMap []map[string]string Map map[string]string MapMap map[string]map[string]string MapStructs map[string]*SliceStruct MapMapStruct map[string]map[string]*SliceStruct MapSlice map[string][]string MapInt map[int]string MapInt8 map[int8]string MapInt16 map[int16]string MapInt32 map[int32]string MapInt64 map[int64]string MapUint map[uint]string MapUint8 map[uint8]string MapUint16 map[uint16]string MapUint32 map[uint32]string MapUint64 map[uint64]string MapFloat32 map[float32]string MapFloat64 map[float64]string MapBool map[bool]string } type Test struct { Inner *Inner CreatedAt *time.Time } now := time.Now() inner := &Inner{ CreatedAt: &now, Slice: []string{"val1", "val2", "val3"}, SliceStructs: []*SliceStruct{{Name: "name1"}, {Name: "name2"}, {Name: "name3"}}, SliceSlice: [][]string{{"1", "2", "3"}, {"4", "5", "6"}, {"7", "8", "9"}}, SliceSliceStruct: [][]*SliceStruct{{{Name: "name1"}, {Name: "name2"}, {Name: "name3"}}, {{Name: "name4"}, {Name: "name5"}, {Name: "name6"}}, {{Name: "name7"}, {Name: "name8"}, {Name: "name9"}}}, SliceMap: []map[string]string{{"key1": "val1", "key2": "val2", "key3": "val3"}, {"key4": "val4", "key5": "val5", "key6": "val6"}}, Map: map[string]string{"key1": "val1", "key2": "val2", "key3": "val3"}, MapStructs: map[string]*SliceStruct{"key1": {Name: "name1"}, "key2": {Name: "name2"}, "key3": {Name: "name3"}}, MapMap: map[string]map[string]string{"key1": {"key1-1": "val1"}, "key2": {"key2-1": "val2"}, "key3": {"key3-1": "val3"}}, MapMapStruct: map[string]map[string]*SliceStruct{"key1": {"key1-1": {Name: "name1"}}, "key2": {"key2-1": {Name: "name2"}}, "key3": {"key3-1": {Name: "name3"}}}, MapSlice: map[string][]string{"key1": {"1", "2", "3"}, "key2": {"4", "5", "6"}, "key3": {"7", "8", "9"}}, MapInt: map[int]string{1: "val1", 2: "val2", 3: "val3"}, MapInt8: map[int8]string{1: "val1", 2: "val2", 3: "val3"}, MapInt16: map[int16]string{1: "val1", 2: "val2", 3: "val3"}, MapInt32: map[int32]string{1: "val1", 2: "val2", 3: "val3"}, MapInt64: map[int64]string{1: "val1", 2: "val2", 3: "val3"}, MapUint: map[uint]string{1: "val1", 2: "val2", 3: "val3"}, MapUint8: map[uint8]string{1: "val1", 2: "val2", 3: "val3"}, MapUint16: map[uint16]string{1: "val1", 2: "val2", 3: "val3"}, MapUint32: map[uint32]string{1: "val1", 2: "val2", 3: "val3"}, MapUint64: map[uint64]string{1: "val1", 2: "val2", 3: "val3"}, MapFloat32: map[float32]string{1.01: "val1", 2.02: "val2", 3.03: "val3"}, MapFloat64: map[float64]string{1.01: "val1", 2.02: "val2", 3.03: "val3"}, MapBool: map[bool]string{true: "val1", false: "val2"}, } test := &Test{ Inner: inner, CreatedAt: &now, } val := reflect.ValueOf(test) vd := New() v := &validate{ v: vd, } current, kind, _, ok := v.getStructFieldOKInternal(val, "Inner.CreatedAt") Equal(t, ok, true) Equal(t, kind, reflect.Struct) tm, ok := current.Interface().(time.Time) Equal(t, ok, true) Equal(t, tm, now) current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.Slice[1]") Equal(t, ok, true) Equal(t, kind, reflect.String) Equal(t, current.String(), "val2") current, _, _, ok = v.getStructFieldOKInternal(val, "Inner.CrazyNonExistantField") Equal(t, ok, false) current, _, _, ok = v.getStructFieldOKInternal(val, "Inner.Slice[101]") Equal(t, ok, false) current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.Map[key3]") Equal(t, ok, true) Equal(t, kind, reflect.String) Equal(t, current.String(), "val3") current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.MapMap[key2][key2-1]") Equal(t, ok, true) Equal(t, kind, reflect.String) Equal(t, current.String(), "val2") current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.MapStructs[key2].Name") Equal(t, ok, true) Equal(t, kind, reflect.String) Equal(t, current.String(), "name2") current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.MapMapStruct[key3][key3-1].Name") Equal(t, ok, true) Equal(t, kind, reflect.String) Equal(t, current.String(), "name3") current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.SliceSlice[2][0]") Equal(t, ok, true) Equal(t, kind, reflect.String) Equal(t, current.String(), "7") current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.SliceSliceStruct[2][1].Name") Equal(t, ok, true) Equal(t, kind, reflect.String) Equal(t, current.String(), "name8") current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.SliceMap[1][key5]") Equal(t, ok, true) Equal(t, kind, reflect.String) Equal(t, current.String(), "val5") current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.MapSlice[key3][2]") Equal(t, ok, true) Equal(t, kind, reflect.String) Equal(t, current.String(), "9") current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.MapInt[2]") Equal(t, ok, true) Equal(t, kind, reflect.String) Equal(t, current.String(), "val2") current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.MapInt8[2]") Equal(t, ok, true) Equal(t, kind, reflect.String) Equal(t, current.String(), "val2") current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.MapInt16[2]") Equal(t, ok, true) Equal(t, kind, reflect.String) Equal(t, current.String(), "val2") current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.MapInt32[2]") Equal(t, ok, true) Equal(t, kind, reflect.String) Equal(t, current.String(), "val2") current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.MapInt64[2]") Equal(t, ok, true) Equal(t, kind, reflect.String) Equal(t, current.String(), "val2") current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.MapUint[2]") Equal(t, ok, true) Equal(t, kind, reflect.String) Equal(t, current.String(), "val2") current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.MapUint8[2]") Equal(t, ok, true) Equal(t, kind, reflect.String) Equal(t, current.String(), "val2") current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.MapUint16[2]") Equal(t, ok, true) Equal(t, kind, reflect.String) Equal(t, current.String(), "val2") current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.MapUint32[2]") Equal(t, ok, true) Equal(t, kind, reflect.String) Equal(t, current.String(), "val2") current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.MapUint64[2]") Equal(t, ok, true) Equal(t, kind, reflect.String) Equal(t, current.String(), "val2") current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.MapFloat32[3.03]") Equal(t, ok, true) Equal(t, kind, reflect.String) Equal(t, current.String(), "val3") current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.MapFloat64[2.02]") Equal(t, ok, true) Equal(t, kind, reflect.String) Equal(t, current.String(), "val2") current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.MapBool[true]") Equal(t, ok, true) Equal(t, kind, reflect.String) Equal(t, current.String(), "val1") inner = &Inner{ CreatedAt: &now, Slice: []string{"val1", "val2", "val3"}, SliceStructs: []*SliceStruct{{Name: "name1"}, {Name: "name2"}, nil}, SliceSlice: [][]string{{"1", "2", "3"}, {"4", "5", "6"}, {"7", "8", "9"}}, SliceSliceStruct: [][]*SliceStruct{{{Name: "name1"}, {Name: "name2"}, {Name: "name3"}}, {{Name: "name4"}, {Name: "name5"}, {Name: "name6"}}, {{Name: "name7"}, {Name: "name8"}, {Name: "name9"}}}, SliceMap: []map[string]string{{"key1": "val1", "key2": "val2", "key3": "val3"}, {"key4": "val4", "key5": "val5", "key6": "val6"}}, Map: map[string]string{"key1": "val1", "key2": "val2", "key3": "val3"}, MapStructs: map[string]*SliceStruct{"key1": {Name: "name1"}, "key2": {Name: "name2"}, "key3": {Name: "name3"}}, MapMap: map[string]map[string]string{"key1": {"key1-1": "val1"}, "key2": {"key2-1": "val2"}, "key3": {"key3-1": "val3"}}, MapMapStruct: map[string]map[string]*SliceStruct{"key1": {"key1-1": {Name: "name1"}}, "key2": {"key2-1": {Name: "name2"}}, "key3": {"key3-1": {Name: "name3"}}}, MapSlice: map[string][]string{"key1": {"1", "2", "3"}, "key2": {"4", "5", "6"}, "key3": {"7", "8", "9"}}, } test = &Test{ Inner: inner, CreatedAt: nil, } val = reflect.ValueOf(test) current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.SliceStructs[2]") Equal(t, ok, true) Equal(t, kind, reflect.Ptr) Equal(t, current.String(), "<*validator.SliceStruct Value>") Equal(t, current.IsNil(), true) current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.SliceStructs[2].Name") Equal(t, ok, false) Equal(t, kind, reflect.Ptr) Equal(t, current.String(), "<*validator.SliceStruct Value>") Equal(t, current.IsNil(), true) PanicMatches(t, func() { v.getStructFieldOKInternal(reflect.ValueOf(1), "crazyinput") }, "Invalid field namespace") } func TestExistsValidation(t *testing.T) { jsonText := "{ \"truthiness2\": true }" type Thing struct { Truthiness *bool `json:"truthiness" validate:"required"` } var ting Thing err := json.Unmarshal([]byte(jsonText), &ting) Equal(t, err, nil) NotEqual(t, ting, nil) Equal(t, ting.Truthiness, nil) validate := New() errs := validate.Struct(ting) NotEqual(t, errs, nil) AssertError(t, errs, "Thing.Truthiness", "Thing.Truthiness", "Truthiness", "Truthiness", "required") jsonText = "{ \"truthiness\": true }" err = json.Unmarshal([]byte(jsonText), &ting) Equal(t, err, nil) NotEqual(t, ting, nil) Equal(t, ting.Truthiness, true) errs = validate.Struct(ting) Equal(t, errs, nil) } func TestSQLValue2Validation(t *testing.T) { validate := New() validate.RegisterCustomTypeFunc(ValidateValuerType, valuer{}, (*driver.Valuer)(nil), sql.NullString{}, sql.NullInt64{}, sql.NullBool{}, sql.NullFloat64{}) validate.RegisterCustomTypeFunc(ValidateCustomType, MadeUpCustomType{}) validate.RegisterCustomTypeFunc(OverrideIntTypeForSomeReason, 1) val := valuer{ Name: "", } errs := validate.Var(val, "required") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "required") val.Name = "Valid Name" errs = validate.VarCtx(context.Background(), val, "required") Equal(t, errs, nil) val.Name = "errorme" PanicMatches(t, func() { _ = validate.Var(val, "required") }, "SQL Driver Valuer error: some kind of error") myVal := valuer{ Name: "", } errs = validate.Var(myVal, "required") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "required") cust := MadeUpCustomType{ FirstName: "Joey", LastName: "Bloggs", } c := CustomMadeUpStruct{MadeUp: cust, OverriddenInt: 2} errs = validate.Struct(c) Equal(t, errs, nil) c.MadeUp.FirstName = "" c.OverriddenInt = 1 errs = validate.Struct(c) NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 2) AssertError(t, errs, "CustomMadeUpStruct.MadeUp", "CustomMadeUpStruct.MadeUp", "MadeUp", "MadeUp", "required") AssertError(t, errs, "CustomMadeUpStruct.OverriddenInt", "CustomMadeUpStruct.OverriddenInt", "OverriddenInt", "OverriddenInt", "gt") } func TestSQLValueValidation(t *testing.T) { validate := New() validate.RegisterCustomTypeFunc(ValidateValuerType, (*driver.Valuer)(nil), valuer{}) validate.RegisterCustomTypeFunc(ValidateCustomType, MadeUpCustomType{}) validate.RegisterCustomTypeFunc(OverrideIntTypeForSomeReason, 1) val := valuer{ Name: "", } errs := validate.Var(val, "required") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "required") val.Name = "Valid Name" errs = validate.Var(val, "required") Equal(t, errs, nil) val.Name = "errorme" PanicMatches(t, func() { errs = validate.Var(val, "required") }, "SQL Driver Valuer error: some kind of error") myVal := valuer{ Name: "", } errs = validate.Var(myVal, "required") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "required") cust := MadeUpCustomType{ FirstName: "Joey", LastName: "Bloggs", } c := CustomMadeUpStruct{MadeUp: cust, OverriddenInt: 2} errs = validate.Struct(c) Equal(t, errs, nil) c.MadeUp.FirstName = "" c.OverriddenInt = 1 errs = validate.Struct(c) NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 2) AssertError(t, errs, "CustomMadeUpStruct.MadeUp", "CustomMadeUpStruct.MadeUp", "MadeUp", "MadeUp", "required") AssertError(t, errs, "CustomMadeUpStruct.OverriddenInt", "CustomMadeUpStruct.OverriddenInt", "OverriddenInt", "OverriddenInt", "gt") } func TestMACValidation(t *testing.T) { 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}, {"00:25:96:FF:FE:12:34:56", true}, {"0025:96FF:FE12:3456", false}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "mac") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d mac failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d mac failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "mac" { t.Fatalf("Index: %d mac failed Error: %s", i, errs) } } } } } func TestIPValidation(t *testing.T) { tests := []struct { param string expected bool }{ {"", false}, {"10.0.0.1", true}, {"172.16.0.1", true}, {"192.168.0.1", true}, {"192.168.255.254", true}, {"192.168.255.256", false}, {"172.16.255.254", true}, {"172.16.256.255", false}, {"2001:cdba:0000:0000:0000:0000:3257:9652", true}, {"2001:cdba:0:0:0:0:3257:9652", true}, {"2001:cdba::3257:9652", true}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "ip") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d ip failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d ip failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "ip" { t.Fatalf("Index: %d ip failed Error: %s", i, errs) } } } } } func TestIPv6Validation(t *testing.T) { tests := []struct { param string expected bool }{ {"10.0.0.1", false}, {"172.16.0.1", false}, {"192.168.0.1", false}, {"192.168.255.254", false}, {"192.168.255.256", false}, {"172.16.255.254", false}, {"172.16.256.255", false}, {"2001:cdba:0000:0000:0000:0000:3257:9652", true}, {"2001:cdba:0:0:0:0:3257:9652", true}, {"2001:cdba::3257:9652", true}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "ipv6") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d ipv6 failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d ipv6 failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "ipv6" { t.Fatalf("Index: %d ipv6 failed Error: %s", i, errs) } } } } } func TestIPv4Validation(t *testing.T) { tests := []struct { param string expected bool }{ {"10.0.0.1", true}, {"172.16.0.1", true}, {"192.168.0.1", true}, {"192.168.255.254", true}, {"192.168.255.256", false}, {"172.16.255.254", true}, {"172.16.256.255", false}, {"2001:cdba:0000:0000:0000:0000:3257:9652", false}, {"2001:cdba:0:0:0:0:3257:9652", false}, {"2001:cdba::3257:9652", false}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "ipv4") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d ipv4 failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d ipv4 failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "ipv4" { t.Fatalf("Index: %d ipv4 failed Error: %s", i, errs) } } } } } func TestCIDRValidation(t *testing.T) { tests := []struct { param string expected bool }{ {"10.0.0.0/0", true}, {"10.0.0.1/8", true}, {"172.16.0.1/16", true}, {"192.168.0.1/24", true}, {"192.168.255.254/24", true}, {"192.168.255.254/48", false}, {"192.168.255.256/24", false}, {"172.16.255.254/16", true}, {"172.16.256.255/16", false}, {"2001:cdba:0000:0000:0000:0000:3257:9652/64", true}, {"2001:cdba:0000:0000:0000:0000:3257:9652/256", false}, {"2001:cdba:0:0:0:0:3257:9652/32", true}, {"2001:cdba::3257:9652/16", true}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "cidr") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d cidr failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d cidr failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "cidr" { t.Fatalf("Index: %d cidr failed Error: %s", i, errs) } } } } } func TestCIDRv6Validation(t *testing.T) { tests := []struct { param string expected bool }{ {"10.0.0.0/0", false}, {"10.0.0.1/8", false}, {"172.16.0.1/16", false}, {"192.168.0.1/24", false}, {"192.168.255.254/24", false}, {"192.168.255.254/48", false}, {"192.168.255.256/24", false}, {"172.16.255.254/16", false}, {"172.16.256.255/16", false}, {"2001:cdba:0000:0000:0000:0000:3257:9652/64", true}, {"2001:cdba:0000:0000:0000:0000:3257:9652/256", false}, {"2001:cdba:0:0:0:0:3257:9652/32", true}, {"2001:cdba::3257:9652/16", true}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "cidrv6") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d cidrv6 failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d cidrv6 failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "cidrv6" { t.Fatalf("Index: %d cidrv6 failed Error: %s", i, errs) } } } } } func TestCIDRv4Validation(t *testing.T) { tests := []struct { param string expected bool }{ {"10.0.0.0/0", true}, {"10.0.0.1/8", true}, {"172.16.0.1/16", true}, {"192.168.0.1/24", true}, {"192.168.255.254/24", true}, {"192.168.255.254/48", false}, {"192.168.255.256/24", false}, {"172.16.255.254/16", true}, {"172.16.256.255/16", false}, {"2001:cdba:0000:0000:0000:0000:3257:9652/64", false}, {"2001:cdba:0000:0000:0000:0000:3257:9652/256", false}, {"2001:cdba:0:0:0:0:3257:9652/32", false}, {"2001:cdba::3257:9652/16", false}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "cidrv4") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d cidrv4 failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d cidrv4 failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "cidrv4" { t.Fatalf("Index: %d cidrv4 failed Error: %s", i, errs) } } } } } func TestTCPAddrValidation(t *testing.T) { tests := []struct { param string expected bool }{ {"", false}, {":80", false}, {"127.0.0.1:80", true}, {"[::1]:80", true}, {"256.0.0.0:1", false}, {"[::1]", false}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "tcp_addr") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d tcp_addr failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d tcp_addr failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "tcp_addr" { t.Fatalf("Index: %d tcp_addr failed Error: %s", i, errs) } } } } } func TestTCP6AddrValidation(t *testing.T) { tests := []struct { param string expected bool }{ {"", false}, {":80", false}, {"127.0.0.1:80", false}, {"[::1]:80", true}, {"256.0.0.0:1", false}, {"[::1]", false}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "tcp6_addr") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d tcp6_addr failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d tcp6_addr failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "tcp6_addr" { t.Fatalf("Index: %d tcp6_addr failed Error: %s", i, errs) } } } } } func TestTCP4AddrValidation(t *testing.T) { tests := []struct { param string expected bool }{ {"", false}, {":80", false}, {"127.0.0.1:80", true}, {"[::1]:80", false}, // https://github.com/golang/go/issues/14037 {"256.0.0.0:1", false}, {"[::1]", false}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "tcp4_addr") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d tcp4_addr failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Log(test.param, IsEqual(errs, nil)) t.Fatalf("Index: %d tcp4_addr failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "tcp4_addr" { t.Fatalf("Index: %d tcp4_addr failed Error: %s", i, errs) } } } } } func TestUDPAddrValidation(t *testing.T) { tests := []struct { param string expected bool }{ {"", false}, {":80", false}, {"127.0.0.1:80", true}, {"[::1]:80", true}, {"256.0.0.0:1", false}, {"[::1]", false}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "udp_addr") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d udp_addr failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d udp_addr failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "udp_addr" { t.Fatalf("Index: %d udp_addr failed Error: %s", i, errs) } } } } } func TestUDP6AddrValidation(t *testing.T) { tests := []struct { param string expected bool }{ {"", false}, {":80", false}, {"127.0.0.1:80", false}, {"[::1]:80", true}, {"256.0.0.0:1", false}, {"[::1]", false}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "udp6_addr") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d udp6_addr failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d udp6_addr failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "udp6_addr" { t.Fatalf("Index: %d udp6_addr failed Error: %s", i, errs) } } } } } func TestUDP4AddrValidation(t *testing.T) { tests := []struct { param string expected bool }{ {"", false}, {":80", false}, {"127.0.0.1:80", true}, {"[::1]:80", false}, // https://github.com/golang/go/issues/14037 {"256.0.0.0:1", false}, {"[::1]", false}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "udp4_addr") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d udp4_addr failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Log(test.param, IsEqual(errs, nil)) t.Fatalf("Index: %d udp4_addr failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "udp4_addr" { t.Fatalf("Index: %d udp4_addr failed Error: %s", i, errs) } } } } } func TestIPAddrValidation(t *testing.T) { tests := []struct { param string expected bool }{ {"", false}, {"127.0.0.1", true}, {"127.0.0.1:80", false}, {"::1", true}, {"256.0.0.0", false}, {"localhost", false}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "ip_addr") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d ip_addr failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d ip_addr failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "ip_addr" { t.Fatalf("Index: %d ip_addr failed Error: %s", i, errs) } } } } } func TestIP6AddrValidation(t *testing.T) { tests := []struct { param string expected bool }{ {"", false}, {"127.0.0.1", false}, // https://github.com/golang/go/issues/14037 {"127.0.0.1:80", false}, {"::1", true}, {"0:0:0:0:0:0:0:1", true}, {"256.0.0.0", false}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "ip6_addr") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d ip6_addr failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d ip6_addr failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "ip6_addr" { t.Fatalf("Index: %d ip6_addr failed Error: %s", i, errs) } } } } } func TestIP4AddrValidation(t *testing.T) { tests := []struct { param string expected bool }{ {"", false}, {"127.0.0.1", true}, {"127.0.0.1:80", false}, {"::1", false}, // https://github.com/golang/go/issues/14037 {"256.0.0.0", false}, {"localhost", false}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "ip4_addr") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d ip4_addr failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Log(test.param, IsEqual(errs, nil)) t.Fatalf("Index: %d ip4_addr failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "ip4_addr" { t.Fatalf("Index: %d ip4_addr failed Error: %s", i, errs) } } } } } func TestUnixAddrValidation(t *testing.T) { tests := []struct { param string expected bool }{ {"", true}, {"v.sock", true}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "unix_addr") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d unix_addr failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Log(test.param, IsEqual(errs, nil)) t.Fatalf("Index: %d unix_addr failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "unix_addr" { t.Fatalf("Index: %d unix_addr failed Error: %s", i, errs) } } } } } func TestSliceMapArrayChanFuncPtrInterfaceRequiredValidation(t *testing.T) { validate := New() var m map[string]string errs := validate.Var(m, "required") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "required") m = map[string]string{} errs = validate.Var(m, "required") Equal(t, errs, nil) var arr [5]string errs = validate.Var(arr, "required") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "required") arr[0] = "ok" errs = validate.Var(arr, "required") Equal(t, errs, nil) var s []string errs = validate.Var(s, "required") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "required") s = []string{} errs = validate.Var(s, "required") Equal(t, errs, nil) var c chan string errs = validate.Var(c, "required") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "required") c = make(chan string) errs = validate.Var(c, "required") Equal(t, errs, nil) var tst *int errs = validate.Var(tst, "required") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "required") one := 1 tst = &one errs = validate.Var(tst, "required") Equal(t, errs, nil) var iface interface{} errs = validate.Var(iface, "required") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "required") errs = validate.Var(iface, "omitempty,required") Equal(t, errs, nil) errs = validate.Var(iface, "") Equal(t, errs, nil) errs = validate.VarWithValue(nil, iface, "") Equal(t, errs, nil) var f func(string) errs = validate.Var(f, "required") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "required") f = func(name string) {} errs = validate.Var(f, "required") Equal(t, errs, nil) } func TestDatePtrValidationIssueValidation(t *testing.T) { type Test struct { LastViewed *time.Time Reminder *time.Time } test := &Test{} validate := New() errs := validate.Struct(test) Equal(t, errs, nil) } func TestCommaAndPipeObfuscationValidation(t *testing.T) { s := "My Name Is, |joeybloggs|" validate := New() errs := validate.Var(s, "excludesall=0x2C") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "excludesall") errs = validate.Var(s, "excludesall=0x7C") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "excludesall") } func TestBadKeyValidation(t *testing.T) { type Test struct { Name string `validate:"required, "` } tst := &Test{ Name: "test", } validate := New() PanicMatches(t, func() { _ = validate.Struct(tst) }, "Undefined validation function ' ' on field 'Name'") type Test2 struct { Name string `validate:"required,,len=2"` } tst2 := &Test2{ Name: "test", } PanicMatches(t, func() { _ = validate.Struct(tst2) }, "Invalid validation tag on field 'Name'") } func TestInterfaceErrValidation(t *testing.T) { var v2 interface{} = 1 var v1 interface{} = v2 validate := New() errs := validate.Var(v1, "len=1") Equal(t, errs, nil) errs = validate.Var(v2, "len=1") Equal(t, errs, nil) type ExternalCMD struct { Userid string `json:"userid"` Action uint32 `json:"action"` Data interface{} `json:"data,omitempty" validate:"required"` } s := &ExternalCMD{ Userid: "123456", Action: 10000, // Data: 1, } errs = validate.Struct(s) NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 1) AssertError(t, errs, "ExternalCMD.Data", "ExternalCMD.Data", "Data", "Data", "required") type ExternalCMD2 struct { Userid string `json:"userid"` Action uint32 `json:"action"` Data interface{} `json:"data,omitempty" validate:"len=1"` } s2 := &ExternalCMD2{ Userid: "123456", Action: 10000, // Data: 1, } errs = validate.Struct(s2) NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 1) AssertError(t, errs, "ExternalCMD2.Data", "ExternalCMD2.Data", "Data", "Data", "len") s3 := &ExternalCMD2{ Userid: "123456", Action: 10000, Data: 2, } errs = validate.Struct(s3) NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 1) AssertError(t, errs, "ExternalCMD2.Data", "ExternalCMD2.Data", "Data", "Data", "len") type Inner struct { Name string `validate:"required"` } inner := &Inner{ Name: "", } s4 := &ExternalCMD{ Userid: "123456", Action: 10000, Data: inner, } errs = validate.Struct(s4) NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 1) AssertError(t, errs, "ExternalCMD.Data.Name", "ExternalCMD.Data.Name", "Name", "Name", "required") type TestMapStructPtr struct { Errs map[int]interface{} `validate:"gt=0,dive,len=2"` } mip := map[int]interface{}{0: &Inner{"ok"}, 3: nil, 4: &Inner{"ok"}} msp := &TestMapStructPtr{ Errs: mip, } errs = validate.Struct(msp) NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 1) AssertError(t, errs, "TestMapStructPtr.Errs[3]", "TestMapStructPtr.Errs[3]", "Errs[3]", "Errs[3]", "len") type TestMultiDimensionalStructs struct { Errs [][]interface{} `validate:"gt=0,dive,dive"` } var errStructArray [][]interface{} errStructArray = append(errStructArray, []interface{}{&Inner{"ok"}, &Inner{""}, &Inner{""}}) errStructArray = append(errStructArray, []interface{}{&Inner{"ok"}, &Inner{""}, &Inner{""}}) tms := &TestMultiDimensionalStructs{ Errs: errStructArray, } errs = validate.Struct(tms) NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 4) AssertError(t, errs, "TestMultiDimensionalStructs.Errs[0][1].Name", "TestMultiDimensionalStructs.Errs[0][1].Name", "Name", "Name", "required") AssertError(t, errs, "TestMultiDimensionalStructs.Errs[0][2].Name", "TestMultiDimensionalStructs.Errs[0][2].Name", "Name", "Name", "required") AssertError(t, errs, "TestMultiDimensionalStructs.Errs[1][1].Name", "TestMultiDimensionalStructs.Errs[1][1].Name", "Name", "Name", "required") AssertError(t, errs, "TestMultiDimensionalStructs.Errs[1][2].Name", "TestMultiDimensionalStructs.Errs[1][2].Name", "Name", "Name", "required") type TestMultiDimensionalStructsPtr2 struct { Errs [][]*Inner `validate:"gt=0,dive,dive,required"` } var errStructPtr2Array [][]*Inner errStructPtr2Array = append(errStructPtr2Array, []*Inner{{"ok"}, {""}, {""}}) errStructPtr2Array = append(errStructPtr2Array, []*Inner{{"ok"}, {""}, {""}}) errStructPtr2Array = append(errStructPtr2Array, []*Inner{{"ok"}, {""}, nil}) tmsp2 := &TestMultiDimensionalStructsPtr2{ Errs: errStructPtr2Array, } errs = validate.Struct(tmsp2) NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 6) AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[0][1].Name", "TestMultiDimensionalStructsPtr2.Errs[0][1].Name", "Name", "Name", "required") AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[0][2].Name", "TestMultiDimensionalStructsPtr2.Errs[0][2].Name", "Name", "Name", "required") AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[1][1].Name", "TestMultiDimensionalStructsPtr2.Errs[1][1].Name", "Name", "Name", "required") AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[1][2].Name", "TestMultiDimensionalStructsPtr2.Errs[1][2].Name", "Name", "Name", "required") AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[2][1].Name", "TestMultiDimensionalStructsPtr2.Errs[2][1].Name", "Name", "Name", "required") AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[2][2]", "TestMultiDimensionalStructsPtr2.Errs[2][2]", "Errs[2][2]", "Errs[2][2]", "required") m := map[int]interface{}{0: "ok", 3: "", 4: "ok"} errs = validate.Var(m, "len=3,dive,len=2") NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 1) AssertError(t, errs, "[3]", "[3]", "[3]", "[3]", "len") errs = validate.Var(m, "len=2,dive,required") NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 1) AssertError(t, errs, "", "", "", "", "len") arr := []interface{}{"ok", "", "ok"} errs = validate.Var(arr, "len=3,dive,len=2") NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 1) AssertError(t, errs, "[1]", "[1]", "[1]", "[1]", "len") errs = validate.Var(arr, "len=2,dive,required") NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 1) AssertError(t, errs, "", "", "", "", "len") type MyStruct struct { A, B string C interface{} } var a MyStruct a.A = "value" a.C = "nu" errs = validate.Struct(a) Equal(t, errs, nil) } func TestMapDiveValidation(t *testing.T) { validate := New() n := map[int]interface{}{0: nil} errs := validate.Var(n, "omitempty,required") Equal(t, errs, nil) m := map[int]string{0: "ok", 3: "", 4: "ok"} errs = validate.Var(m, "len=3,dive,required") NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 1) AssertError(t, errs, "[3]", "[3]", "[3]", "[3]", "required") errs = validate.Var(m, "len=2,dive,required") NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 1) AssertError(t, errs, "", "", "", "", "len") type Inner struct { Name string `validate:"required"` } type TestMapStruct struct { Errs map[int]Inner `validate:"gt=0,dive"` } mi := map[int]Inner{0: {"ok"}, 3: {""}, 4: {"ok"}} ms := &TestMapStruct{ Errs: mi, } errs = validate.Struct(ms) NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 1) AssertError(t, errs, "TestMapStruct.Errs[3].Name", "TestMapStruct.Errs[3].Name", "Name", "Name", "required") // for full test coverage s := fmt.Sprint(errs.Error()) NotEqual(t, s, "") type TestMapTimeStruct struct { Errs map[int]*time.Time `validate:"gt=0,dive,required"` } t1 := time.Now().UTC() mta := map[int]*time.Time{0: &t1, 3: nil, 4: nil} mt := &TestMapTimeStruct{ Errs: mta, } errs = validate.Struct(mt) NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 2) AssertError(t, errs, "TestMapTimeStruct.Errs[3]", "TestMapTimeStruct.Errs[3]", "Errs[3]", "Errs[3]", "required") AssertError(t, errs, "TestMapTimeStruct.Errs[4]", "TestMapTimeStruct.Errs[4]", "Errs[4]", "Errs[4]", "required") type TestMapStructPtr struct { Errs map[int]*Inner `validate:"gt=0,dive,required"` } mip := map[int]*Inner{0: {"ok"}, 3: nil, 4: {"ok"}} msp := &TestMapStructPtr{ Errs: mip, } errs = validate.Struct(msp) NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 1) AssertError(t, errs, "TestMapStructPtr.Errs[3]", "TestMapStructPtr.Errs[3]", "Errs[3]", "Errs[3]", "required") type TestMapStructPtr2 struct { Errs map[int]*Inner `validate:"gt=0,dive,omitempty,required"` } mip2 := map[int]*Inner{0: {"ok"}, 3: nil, 4: {"ok"}} msp2 := &TestMapStructPtr2{ Errs: mip2, } errs = validate.Struct(msp2) Equal(t, errs, nil) v2 := New() v2.RegisterTagNameFunc(func(fld reflect.StructField) string { name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] if name == "-" { return "" } return name }) type MapDiveJSONTest struct { Map map[string]string `validate:"required,gte=1,dive,gte=1" json:"MyName"` } mdjt := &MapDiveJSONTest{ Map: map[string]string{ "Key1": "Value1", "Key2": "", }, } err := v2.Struct(mdjt) NotEqual(t, err, nil) errs = err.(ValidationErrors) fe := getError(errs, "MapDiveJSONTest.MyName[Key2]", "MapDiveJSONTest.Map[Key2]") NotEqual(t, fe, nil) Equal(t, fe.Tag(), "gte") Equal(t, fe.ActualTag(), "gte") Equal(t, fe.Field(), "MyName[Key2]") Equal(t, fe.StructField(), "Map[Key2]") } func TestArrayDiveValidation(t *testing.T) { validate := New() arr := []string{"ok", "", "ok"} errs := validate.Var(arr, "len=3,dive,required") NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 1) AssertError(t, errs, "[1]", "[1]", "[1]", "[1]", "required") errs = validate.Var(arr, "len=2,dive,required") NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 1) AssertError(t, errs, "", "", "", "", "len") type BadDive struct { Name string `validate:"dive"` } bd := &BadDive{ Name: "TEST", } PanicMatches(t, func() { _ = validate.Struct(bd) }, "dive error! can't dive on a non slice or map") type Test struct { Errs []string `validate:"gt=0,dive,required"` } test := &Test{ Errs: []string{"ok", "", "ok"}, } errs = validate.Struct(test) NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 1) AssertError(t, errs, "Test.Errs[1]", "Test.Errs[1]", "Errs[1]", "Errs[1]", "required") test = &Test{ Errs: []string{"ok", "ok", ""}, } errs = validate.Struct(test) NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 1) AssertError(t, errs, "Test.Errs[2]", "Test.Errs[2]", "Errs[2]", "Errs[2]", "required") type TestMultiDimensional struct { Errs [][]string `validate:"gt=0,dive,dive,required"` } var errArray [][]string errArray = append(errArray, []string{"ok", "", ""}) errArray = append(errArray, []string{"ok", "", ""}) tm := &TestMultiDimensional{ Errs: errArray, } errs = validate.Struct(tm) NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 4) AssertError(t, errs, "TestMultiDimensional.Errs[0][1]", "TestMultiDimensional.Errs[0][1]", "Errs[0][1]", "Errs[0][1]", "required") AssertError(t, errs, "TestMultiDimensional.Errs[0][2]", "TestMultiDimensional.Errs[0][2]", "Errs[0][2]", "Errs[0][2]", "required") AssertError(t, errs, "TestMultiDimensional.Errs[1][1]", "TestMultiDimensional.Errs[1][1]", "Errs[1][1]", "Errs[1][1]", "required") AssertError(t, errs, "TestMultiDimensional.Errs[1][2]", "TestMultiDimensional.Errs[1][2]", "Errs[1][2]", "Errs[1][2]", "required") type Inner struct { Name string `validate:"required"` } type TestMultiDimensionalStructs struct { Errs [][]Inner `validate:"gt=0,dive,dive"` } var errStructArray [][]Inner errStructArray = append(errStructArray, []Inner{{"ok"}, {""}, {""}}) errStructArray = append(errStructArray, []Inner{{"ok"}, {""}, {""}}) tms := &TestMultiDimensionalStructs{ Errs: errStructArray, } errs = validate.Struct(tms) NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 4) AssertError(t, errs, "TestMultiDimensionalStructs.Errs[0][1].Name", "TestMultiDimensionalStructs.Errs[0][1].Name", "Name", "Name", "required") AssertError(t, errs, "TestMultiDimensionalStructs.Errs[0][2].Name", "TestMultiDimensionalStructs.Errs[0][2].Name", "Name", "Name", "required") AssertError(t, errs, "TestMultiDimensionalStructs.Errs[1][1].Name", "TestMultiDimensionalStructs.Errs[1][1].Name", "Name", "Name", "required") AssertError(t, errs, "TestMultiDimensionalStructs.Errs[1][2].Name", "TestMultiDimensionalStructs.Errs[1][2].Name", "Name", "Name", "required") type TestMultiDimensionalStructsPtr struct { Errs [][]*Inner `validate:"gt=0,dive,dive"` } var errStructPtrArray [][]*Inner errStructPtrArray = append(errStructPtrArray, []*Inner{{"ok"}, {""}, {""}}) errStructPtrArray = append(errStructPtrArray, []*Inner{{"ok"}, {""}, {""}}) errStructPtrArray = append(errStructPtrArray, []*Inner{{"ok"}, {""}, nil}) tmsp := &TestMultiDimensionalStructsPtr{ Errs: errStructPtrArray, } errs = validate.Struct(tmsp) NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 5) AssertError(t, errs, "TestMultiDimensionalStructsPtr.Errs[0][1].Name", "TestMultiDimensionalStructsPtr.Errs[0][1].Name", "Name", "Name", "required") AssertError(t, errs, "TestMultiDimensionalStructsPtr.Errs[0][2].Name", "TestMultiDimensionalStructsPtr.Errs[0][2].Name", "Name", "Name", "required") AssertError(t, errs, "TestMultiDimensionalStructsPtr.Errs[1][1].Name", "TestMultiDimensionalStructsPtr.Errs[1][1].Name", "Name", "Name", "required") AssertError(t, errs, "TestMultiDimensionalStructsPtr.Errs[1][2].Name", "TestMultiDimensionalStructsPtr.Errs[1][2].Name", "Name", "Name", "required") AssertError(t, errs, "TestMultiDimensionalStructsPtr.Errs[2][1].Name", "TestMultiDimensionalStructsPtr.Errs[2][1].Name", "Name", "Name", "required") // for full test coverage s := fmt.Sprint(errs.Error()) NotEqual(t, s, "") type TestMultiDimensionalStructsPtr2 struct { Errs [][]*Inner `validate:"gt=0,dive,dive,required"` } var errStructPtr2Array [][]*Inner errStructPtr2Array = append(errStructPtr2Array, []*Inner{{"ok"}, {""}, {""}}) errStructPtr2Array = append(errStructPtr2Array, []*Inner{{"ok"}, {""}, {""}}) errStructPtr2Array = append(errStructPtr2Array, []*Inner{{"ok"}, {""}, nil}) tmsp2 := &TestMultiDimensionalStructsPtr2{ Errs: errStructPtr2Array, } errs = validate.Struct(tmsp2) NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 6) AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[0][1].Name", "TestMultiDimensionalStructsPtr2.Errs[0][1].Name", "Name", "Name", "required") AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[0][2].Name", "TestMultiDimensionalStructsPtr2.Errs[0][2].Name", "Name", "Name", "required") AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[1][1].Name", "TestMultiDimensionalStructsPtr2.Errs[1][1].Name", "Name", "Name", "required") AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[1][2].Name", "TestMultiDimensionalStructsPtr2.Errs[1][2].Name", "Name", "Name", "required") AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[2][1].Name", "TestMultiDimensionalStructsPtr2.Errs[2][1].Name", "Name", "Name", "required") AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[2][2]", "TestMultiDimensionalStructsPtr2.Errs[2][2]", "Errs[2][2]", "Errs[2][2]", "required") type TestMultiDimensionalStructsPtr3 struct { Errs [][]*Inner `validate:"gt=0,dive,dive,omitempty"` } var errStructPtr3Array [][]*Inner errStructPtr3Array = append(errStructPtr3Array, []*Inner{{"ok"}, {""}, {""}}) errStructPtr3Array = append(errStructPtr3Array, []*Inner{{"ok"}, {""}, {""}}) errStructPtr3Array = append(errStructPtr3Array, []*Inner{{"ok"}, {""}, nil}) tmsp3 := &TestMultiDimensionalStructsPtr3{ Errs: errStructPtr3Array, } errs = validate.Struct(tmsp3) NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 5) AssertError(t, errs, "TestMultiDimensionalStructsPtr3.Errs[0][1].Name", "TestMultiDimensionalStructsPtr3.Errs[0][1].Name", "Name", "Name", "required") AssertError(t, errs, "TestMultiDimensionalStructsPtr3.Errs[0][2].Name", "TestMultiDimensionalStructsPtr3.Errs[0][2].Name", "Name", "Name", "required") AssertError(t, errs, "TestMultiDimensionalStructsPtr3.Errs[1][1].Name", "TestMultiDimensionalStructsPtr3.Errs[1][1].Name", "Name", "Name", "required") AssertError(t, errs, "TestMultiDimensionalStructsPtr3.Errs[1][2].Name", "TestMultiDimensionalStructsPtr3.Errs[1][2].Name", "Name", "Name", "required") AssertError(t, errs, "TestMultiDimensionalStructsPtr3.Errs[2][1].Name", "TestMultiDimensionalStructsPtr3.Errs[2][1].Name", "Name", "Name", "required") type TestMultiDimensionalTimeTime struct { Errs [][]*time.Time `validate:"gt=0,dive,dive,required"` } var errTimePtr3Array [][]*time.Time t1 := time.Now().UTC() t2 := time.Now().UTC() t3 := time.Now().UTC().Add(time.Hour * 24) errTimePtr3Array = append(errTimePtr3Array, []*time.Time{&t1, &t2, &t3}) errTimePtr3Array = append(errTimePtr3Array, []*time.Time{&t1, &t2, nil}) errTimePtr3Array = append(errTimePtr3Array, []*time.Time{&t1, nil, nil}) tmtp3 := &TestMultiDimensionalTimeTime{ Errs: errTimePtr3Array, } errs = validate.Struct(tmtp3) NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 3) AssertError(t, errs, "TestMultiDimensionalTimeTime.Errs[1][2]", "TestMultiDimensionalTimeTime.Errs[1][2]", "Errs[1][2]", "Errs[1][2]", "required") AssertError(t, errs, "TestMultiDimensionalTimeTime.Errs[2][1]", "TestMultiDimensionalTimeTime.Errs[2][1]", "Errs[2][1]", "Errs[2][1]", "required") AssertError(t, errs, "TestMultiDimensionalTimeTime.Errs[2][2]", "TestMultiDimensionalTimeTime.Errs[2][2]", "Errs[2][2]", "Errs[2][2]", "required") type TestMultiDimensionalTimeTime2 struct { Errs [][]*time.Time `validate:"gt=0,dive,dive,required"` } var errTimeArray [][]*time.Time t1 = time.Now().UTC() t2 = time.Now().UTC() t3 = time.Now().UTC().Add(time.Hour * 24) errTimeArray = append(errTimeArray, []*time.Time{&t1, &t2, &t3}) errTimeArray = append(errTimeArray, []*time.Time{&t1, &t2, nil}) errTimeArray = append(errTimeArray, []*time.Time{&t1, nil, nil}) tmtp := &TestMultiDimensionalTimeTime2{ Errs: errTimeArray, } errs = validate.Struct(tmtp) NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 3) AssertError(t, errs, "TestMultiDimensionalTimeTime2.Errs[1][2]", "TestMultiDimensionalTimeTime2.Errs[1][2]", "Errs[1][2]", "Errs[1][2]", "required") AssertError(t, errs, "TestMultiDimensionalTimeTime2.Errs[2][1]", "TestMultiDimensionalTimeTime2.Errs[2][1]", "Errs[2][1]", "Errs[2][1]", "required") AssertError(t, errs, "TestMultiDimensionalTimeTime2.Errs[2][2]", "TestMultiDimensionalTimeTime2.Errs[2][2]", "Errs[2][2]", "Errs[2][2]", "required") } func TestNilStructPointerValidation(t *testing.T) { type Inner struct { Data string } type Outer struct { Inner *Inner `validate:"omitempty"` } inner := &Inner{ Data: "test", } outer := &Outer{ Inner: inner, } validate := New() errs := validate.Struct(outer) Equal(t, errs, nil) outer = &Outer{ Inner: nil, } errs = validate.Struct(outer) Equal(t, errs, nil) type Inner2 struct { Data string } type Outer2 struct { Inner2 *Inner2 `validate:"required"` } inner2 := &Inner2{ Data: "test", } outer2 := &Outer2{ Inner2: inner2, } errs = validate.Struct(outer2) Equal(t, errs, nil) outer2 = &Outer2{ Inner2: nil, } errs = validate.Struct(outer2) NotEqual(t, errs, nil) AssertError(t, errs, "Outer2.Inner2", "Outer2.Inner2", "Inner2", "Inner2", "required") type Inner3 struct { Data string } type Outer3 struct { Inner3 *Inner3 } inner3 := &Inner3{ Data: "test", } outer3 := &Outer3{ Inner3: inner3, } errs = validate.Struct(outer3) Equal(t, errs, nil) type Inner4 struct { Data string } type Outer4 struct { Inner4 *Inner4 `validate:"-"` } inner4 := &Inner4{ Data: "test", } outer4 := &Outer4{ Inner4: inner4, } errs = validate.Struct(outer4) Equal(t, errs, nil) } func TestSSNValidation(t *testing.T) { tests := []struct { param string expected bool }{ {"", false}, {"00-90-8787", false}, {"66690-76", false}, {"191 60 2869", true}, {"191-60-2869", true}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "ssn") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d SSN failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d SSN failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "ssn" { t.Fatalf("Index: %d Latitude failed Error: %s", i, errs) } } } } } func TestLongitudeValidation(t *testing.T) { tests := []struct { param interface{} expected bool }{ {"", false}, {"-180.000", true}, {"180.1", false}, {"+73.234", true}, {"+382.3811", false}, {"23.11111111", true}, {uint(180), true}, {float32(-180.0), true}, {-180, true}, {180.1, false}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "longitude") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d Longitude failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d Longitude failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "longitude" { t.Fatalf("Index: %d Longitude failed Error: %s", i, errs) } } } } PanicMatches(t, func() { _ = validate.Var(true, "longitude") }, "Bad field type bool") } func TestLatitudeValidation(t *testing.T) { tests := []struct { param interface{} expected bool }{ {"", false}, {"-90.000", true}, {"+90", true}, {"47.1231231", true}, {"+99.9", false}, {"108", false}, {uint(90), true}, {float32(-90.0), true}, {-90, true}, {90.1, false}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "latitude") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d Latitude failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d Latitude failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "latitude" { t.Fatalf("Index: %d Latitude failed Error: %s", i, errs) } } } } PanicMatches(t, func() { _ = validate.Var(true, "latitude") }, "Bad field type bool") } func TestDataURIValidation(t *testing.T) { tests := []struct { param string expected bool }{ {"data:image/png;base64,TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4=", true}, {"data:text/plain;base64,Vml2YW11cyBmZXJtZW50dW0gc2VtcGVyIHBvcnRhLg==", true}, {"image/gif;base64,U3VzcGVuZGlzc2UgbGVjdHVzIGxlbw==", false}, {"data:image/gif;base64,MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuMPNS1Ufof9EW/M98FNw" + "UAKrwflsqVxaxQjBQnHQmiI7Vac40t8x7pIb8gLGV6wL7sBTJiPovJ0V7y7oc0Ye" + "rhKh0Rm4skP2z/jHwwZICgGzBvA0rH8xlhUiTvcwDCJ0kc+fh35hNt8srZQM4619" + "FTgB66Xmp4EtVyhpQV+t02g6NzK72oZI0vnAvqhpkxLeLiMCyrI416wHm5Tkukhx" + "QmcL2a6hNOyu0ixX/x2kSFXApEnVrJ+/IxGyfyw8kf4N2IZpW5nEP847lpfj0SZZ" + "Fwrd1mnfnDbYohX2zRptLy2ZUn06Qo9pkG5ntvFEPo9bfZeULtjYzIl6K8gJ2uGZ" + "HQIDAQAB", true}, {"data:image/png;base64,12345", false}, {"", false}, {"data:text,:;base85,U3VzcGVuZGlzc2UgbGVjdHVzIGxlbw==", false}, {"data:image/jpeg;key=value;base64,UEsDBBQAAAAI", true}, {"data:image/jpeg;key=value,UEsDBBQAAAAI", true}, {"data:;base64;sdfgsdfgsdfasdfa=s,UEsDBBQAAAAI", true}, {"data:,UEsDBBQAAAAI", true}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "datauri") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d DataURI failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d DataURI failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "datauri" { t.Fatalf("Index: %d DataURI failed Error: %s", i, errs) } } } } } func TestMultibyteValidation(t *testing.T) { tests := []struct { param string expected bool }{ {"", true}, {"abc", false}, {"123", false}, {"<>@;.-=", false}, {"ひらがな・カタカナ、.漢字", true}, {"あいうえお foobar", true}, {"test@example.com", true}, {"test@example.com", true}, {"1234abcDExyz", true}, {"カタカナ", true}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "multibyte") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d Multibyte failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d Multibyte failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "multibyte" { t.Fatalf("Index: %d Multibyte failed Error: %s", i, errs) } } } } } func TestPrintableASCIIValidation(t *testing.T) { tests := []struct { param string expected bool }{ {"", true}, {"foobar", false}, {"xyz098", false}, {"123456", false}, {"カタカナ", false}, {"foobar", true}, {"0987654321", true}, {"test@example.com", true}, {"1234abcDEF", true}, {"newline\n", false}, {"\x19test\x7F", false}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "printascii") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d Printable ASCII failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d Printable ASCII failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "printascii" { t.Fatalf("Index: %d Printable ASCII failed Error: %s", i, errs) } } } } } func TestASCIIValidation(t *testing.T) { tests := []struct { param string expected bool }{ {"", true}, {"foobar", false}, {"xyz098", false}, {"123456", false}, {"カタカナ", false}, {"foobar", true}, {"0987654321", true}, {"test@example.com", true}, {"1234abcDEF", true}, {"", true}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "ascii") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d ASCII failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d ASCII failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "ascii" { t.Fatalf("Index: %d ASCII failed Error: %s", i, errs) } } } } } func TestUUID5Validation(t *testing.T) { 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}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "uuid5") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d UUID5 failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d UUID5 failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "uuid5" { t.Fatalf("Index: %d UUID5 failed Error: %s", i, errs) } } } } } func TestUUID4Validation(t *testing.T) { 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}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "uuid4") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d UUID4 failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d UUID4 failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "uuid4" { t.Fatalf("Index: %d UUID4 failed Error: %s", i, errs) } } } } } func TestUUID3Validation(t *testing.T) { 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}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "uuid3") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d UUID3 failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d UUID3 failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "uuid3" { t.Fatalf("Index: %d UUID3 failed Error: %s", i, errs) } } } } } func TestUUIDValidation(t *testing.T) { 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}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "uuid") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d UUID failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d UUID failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "uuid" { t.Fatalf("Index: %d UUID failed Error: %s", i, errs) } } } } } func TestUUID5RFC4122Validation(t *testing.T) { 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}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "uuid5_rfc4122") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d UUID5RFC4122 failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d UUID5RFC4122 failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "uuid5_rfc4122" { t.Fatalf("Index: %d UUID5RFC4122 failed Error: %s", i, errs) } } } } } func TestUUID4RFC4122Validation(t *testing.T) { 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}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "uuid4_rfc4122") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d UUID4RFC4122 failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d UUID4RFC4122 failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "uuid4_rfc4122" { t.Fatalf("Index: %d UUID4RFC4122 failed Error: %s", i, errs) } } } } } func TestUUID3RFC4122Validation(t *testing.T) { 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}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "uuid3_rfc4122") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d UUID3RFC4122 failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d UUID3RFC4122 failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "uuid3_rfc4122" { t.Fatalf("Index: %d UUID3RFC4122 failed Error: %s", i, errs) } } } } } func TestUUIDRFC4122Validation(t *testing.T) { 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}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "uuid_rfc4122") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d UUIDRFC4122 failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d UUIDRFC4122 failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "uuid_rfc4122" { t.Fatalf("Index: %d UUIDRFC4122 failed Error: %s", i, errs) } } } } } func TestISBNValidation(t *testing.T) { 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}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "isbn") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d ISBN failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d ISBN failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "isbn" { t.Fatalf("Index: %d ISBN failed Error: %s", i, errs) } } } } } func TestISBN13Validation(t *testing.T) { 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}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "isbn13") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d ISBN13 failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d ISBN13 failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "isbn13" { t.Fatalf("Index: %d ISBN13 failed Error: %s", i, errs) } } } } } func TestISBN10Validation(t *testing.T) { 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}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "isbn10") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d ISBN10 failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d ISBN10 failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "isbn10" { t.Fatalf("Index: %d ISBN10 failed Error: %s", i, errs) } } } } } func TestExcludesRuneValidation(t *testing.T) { tests := []struct { Value string `validate:"excludesrune=☻"` Tag string ExpectedNil bool }{ {Value: "a☺b☻c☹d", Tag: "excludesrune=☻", ExpectedNil: false}, {Value: "abcd", Tag: "excludesrune=☻", ExpectedNil: true}, } validate := New() for i, s := range tests { errs := validate.Var(s.Value, s.Tag) if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { t.Fatalf("Index: %d failed Error: %s", i, errs) } errs = validate.Struct(s) if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { t.Fatalf("Index: %d failed Error: %s", i, errs) } } } func TestExcludesAllValidation(t *testing.T) { tests := []struct { Value string `validate:"excludesall=@!{}[]"` Tag string ExpectedNil bool }{ {Value: "abcd@!jfk", Tag: "excludesall=@!{}[]", ExpectedNil: false}, {Value: "abcdefg", Tag: "excludesall=@!{}[]", ExpectedNil: true}, } validate := New() for i, s := range tests { errs := validate.Var(s.Value, s.Tag) if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { t.Fatalf("Index: %d failed Error: %s", i, errs) } errs = validate.Struct(s) if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { t.Fatalf("Index: %d failed Error: %s", i, errs) } } username := "joeybloggs " errs := validate.Var(username, "excludesall=@ ") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "excludesall") excluded := "," errs = validate.Var(excluded, "excludesall=!@#$%^&*()_+.0x2C?") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "excludesall") excluded = "=" errs = validate.Var(excluded, "excludesall=!@#$%^&*()_+.0x2C=?") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "excludesall") } func TestExcludesValidation(t *testing.T) { tests := []struct { Value string `validate:"excludes=@"` Tag string ExpectedNil bool }{ {Value: "abcd@!jfk", Tag: "excludes=@", ExpectedNil: false}, {Value: "abcdq!jfk", Tag: "excludes=@", ExpectedNil: true}, } validate := New() for i, s := range tests { errs := validate.Var(s.Value, s.Tag) if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { t.Fatalf("Index: %d failed Error: %s", i, errs) } errs = validate.Struct(s) if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { t.Fatalf("Index: %d failed Error: %s", i, errs) } } } func TestContainsRuneValidation(t *testing.T) { tests := []struct { Value string `validate:"containsrune=☻"` Tag string ExpectedNil bool }{ {Value: "a☺b☻c☹d", Tag: "containsrune=☻", ExpectedNil: true}, {Value: "abcd", Tag: "containsrune=☻", ExpectedNil: false}, } validate := New() for i, s := range tests { errs := validate.Var(s.Value, s.Tag) if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { t.Fatalf("Index: %d failed Error: %s", i, errs) } errs = validate.Struct(s) if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { t.Fatalf("Index: %d failed Error: %s", i, errs) } } } func TestContainsAnyValidation(t *testing.T) { tests := []struct { Value string `validate:"containsany=@!{}[]"` Tag string ExpectedNil bool }{ {Value: "abcd@!jfk", Tag: "containsany=@!{}[]", ExpectedNil: true}, {Value: "abcdefg", Tag: "containsany=@!{}[]", ExpectedNil: false}, } validate := New() for i, s := range tests { errs := validate.Var(s.Value, s.Tag) if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { t.Fatalf("Index: %d failed Error: %s", i, errs) } errs = validate.Struct(s) if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { t.Fatalf("Index: %d failed Error: %s", i, errs) } } } func TestContainsValidation(t *testing.T) { tests := []struct { Value string `validate:"contains=@"` Tag string ExpectedNil bool }{ {Value: "abcd@!jfk", Tag: "contains=@", ExpectedNil: true}, {Value: "abcdq!jfk", Tag: "contains=@", ExpectedNil: false}, } validate := New() for i, s := range tests { errs := validate.Var(s.Value, s.Tag) if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { t.Fatalf("Index: %d failed Error: %s", i, errs) } errs = validate.Struct(s) if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { t.Fatalf("Index: %d failed Error: %s", i, errs) } } } func TestIsNeFieldValidation(t *testing.T) { var errs error validate := New() var j uint64 var k float64 s := "abcd" i := 1 j = 1 k = 1.543 arr := []string{"test"} now := time.Now().UTC() var j2 uint64 var k2 float64 s2 := "abcdef" i2 := 3 j2 = 2 k2 = 1.5434456 arr2 := []string{"test", "test2"} arr3 := []string{"test"} now2 := now errs = validate.VarWithValue(s, s2, "nefield") Equal(t, errs, nil) errs = validate.VarWithValue(i2, i, "nefield") Equal(t, errs, nil) errs = validate.VarWithValue(j2, j, "nefield") Equal(t, errs, nil) errs = validate.VarWithValue(k2, k, "nefield") Equal(t, errs, nil) errs = validate.VarWithValue(arr2, arr, "nefield") Equal(t, errs, nil) errs = validate.VarWithValue(now2, now, "nefield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "nefield") errs = validate.VarWithValue(arr3, arr, "nefield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "nefield") type Test struct { Start *time.Time `validate:"nefield=End"` End *time.Time } sv := &Test{ Start: &now, End: &now, } errs = validate.Struct(sv) NotEqual(t, errs, nil) AssertError(t, errs, "Test.Start", "Test.Start", "Start", "Start", "nefield") now3 := time.Now().UTC() sv = &Test{ Start: &now, End: &now3, } errs = validate.Struct(sv) Equal(t, errs, nil) errs = validate.VarWithValue(nil, 1, "nefield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "nefield") errs = validate.VarWithValue(sv, now, "nefield") Equal(t, errs, nil) type Test2 struct { Start *time.Time `validate:"nefield=NonExistantField"` End *time.Time } sv2 := &Test2{ Start: &now, End: &now, } errs = validate.Struct(sv2) Equal(t, errs, nil) type Other struct { Value string } type Test3 struct { Value Other Time time.Time `validate:"nefield=Value"` } tst := Test3{ Value: Other{Value: "StringVal"}, Time: now, } errs = validate.Struct(tst) Equal(t, errs, nil) // Tests for time.Duration type. // -- Validations for variables of time.Duration type. errs = validate.VarWithValue(time.Hour, time.Hour-time.Minute, "nefield") Equal(t, errs, nil) errs = validate.VarWithValue(time.Hour, time.Hour+time.Minute, "nefield") Equal(t, errs, nil) errs = validate.VarWithValue(time.Hour, time.Hour, "nefield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "nefield") errs = validate.VarWithValue(time.Duration(0), time.Duration(0), "omitempty,nefield") Equal(t, errs, nil) // -- Validations for a struct with time.Duration type fields. type TimeDurationTest struct { First time.Duration `validate:"nefield=Second"` Second time.Duration } var timeDurationTest *TimeDurationTest timeDurationTest = &TimeDurationTest{time.Hour, time.Hour - time.Minute} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) timeDurationTest = &TimeDurationTest{time.Hour, time.Hour + time.Minute} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) timeDurationTest = &TimeDurationTest{time.Hour, time.Hour} errs = validate.Struct(timeDurationTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeDurationTest.First", "TimeDurationTest.First", "First", "First", "nefield") type TimeDurationOmitemptyTest struct { First time.Duration `validate:"omitempty,nefield=Second"` Second time.Duration } timeDurationOmitemptyTest := &TimeDurationOmitemptyTest{time.Duration(0), time.Duration(0)} errs = validate.Struct(timeDurationOmitemptyTest) Equal(t, errs, nil) } func TestIsNeValidation(t *testing.T) { var errs error validate := New() var j uint64 var k float64 s := "abcdef" i := 3 j = 2 k = 1.5434 arr := []string{"test"} now := time.Now().UTC() errs = validate.Var(s, "ne=abcd") Equal(t, errs, nil) errs = validate.Var(i, "ne=1") Equal(t, errs, nil) errs = validate.Var(j, "ne=1") Equal(t, errs, nil) errs = validate.Var(k, "ne=1.543") Equal(t, errs, nil) errs = validate.Var(arr, "ne=2") Equal(t, errs, nil) errs = validate.Var(arr, "ne=1") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "ne") PanicMatches(t, func() { _ = validate.Var(now, "ne=now") }, "Bad field type time.Time") // Tests for time.Duration type. // -- Validations for a variable of time.Duration type. errs = validate.Var(time.Hour-time.Minute, "ne=1h") Equal(t, errs, nil) errs = validate.Var(time.Hour+time.Minute, "ne=1h") Equal(t, errs, nil) errs = validate.Var(time.Hour, "ne=1h") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "ne") errs = validate.Var(time.Duration(0), "omitempty,ne=0") Equal(t, errs, nil) // -- Validations for a struct with a time.Duration type field. type TimeDurationTest struct { Duration time.Duration `validate:"ne=1h"` } var timeDurationTest *TimeDurationTest timeDurationTest = &TimeDurationTest{time.Hour - time.Minute} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) timeDurationTest = &TimeDurationTest{time.Hour + time.Minute} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) timeDurationTest = &TimeDurationTest{time.Hour} errs = validate.Struct(timeDurationTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeDurationTest.Duration", "TimeDurationTest.Duration", "Duration", "Duration", "ne") type TimeDurationOmitemptyTest struct { Duration time.Duration `validate:"omitempty,ne=0"` } timeDurationOmitemptyTest := &TimeDurationOmitemptyTest{time.Duration(0)} errs = validate.Struct(timeDurationOmitemptyTest) Equal(t, errs, nil) } func TestIsEqFieldValidation(t *testing.T) { var errs error validate := New() var j uint64 var k float64 s := "abcd" i := 1 j = 1 k = 1.543 arr := []string{"test"} now := time.Now().UTC() var j2 uint64 var k2 float64 s2 := "abcd" i2 := 1 j2 = 1 k2 = 1.543 arr2 := []string{"test"} arr3 := []string{"test", "test2"} now2 := now errs = validate.VarWithValue(s, s2, "eqfield") Equal(t, errs, nil) errs = validate.VarWithValue(i2, i, "eqfield") Equal(t, errs, nil) errs = validate.VarWithValue(j2, j, "eqfield") Equal(t, errs, nil) errs = validate.VarWithValue(k2, k, "eqfield") Equal(t, errs, nil) errs = validate.VarWithValue(arr2, arr, "eqfield") Equal(t, errs, nil) errs = validate.VarWithValue(now2, now, "eqfield") Equal(t, errs, nil) errs = validate.VarWithValue(arr3, arr, "eqfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "eqfield") type Test struct { Start *time.Time `validate:"eqfield=End"` End *time.Time } sv := &Test{ Start: &now, End: &now, } errs = validate.Struct(sv) Equal(t, errs, nil) now3 := time.Now().UTC() sv = &Test{ Start: &now, End: &now3, } errs = validate.Struct(sv) NotEqual(t, errs, nil) AssertError(t, errs, "Test.Start", "Test.Start", "Start", "Start", "eqfield") errs = validate.VarWithValue(nil, 1, "eqfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "eqfield") channel := make(chan string) errs = validate.VarWithValue(5, channel, "eqfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "eqfield") errs = validate.VarWithValue(5, now, "eqfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "eqfield") type Test2 struct { Start *time.Time `validate:"eqfield=NonExistantField"` End *time.Time } sv2 := &Test2{ Start: &now, End: &now, } errs = validate.Struct(sv2) NotEqual(t, errs, nil) AssertError(t, errs, "Test2.Start", "Test2.Start", "Start", "Start", "eqfield") type Inner struct { Name string } type TStruct struct { Inner *Inner CreatedAt *time.Time `validate:"eqfield=Inner"` } inner := &Inner{ Name: "NAME", } test := &TStruct{ Inner: inner, CreatedAt: &now, } errs = validate.Struct(test) NotEqual(t, errs, nil) AssertError(t, errs, "TStruct.CreatedAt", "TStruct.CreatedAt", "CreatedAt", "CreatedAt", "eqfield") // Tests for time.Duration type. // -- Validations for variables of time.Duration type. errs = validate.VarWithValue(time.Hour, time.Hour, "eqfield") Equal(t, errs, nil) errs = validate.VarWithValue(time.Hour, time.Hour-time.Minute, "eqfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "eqfield") errs = validate.VarWithValue(time.Hour, time.Hour+time.Minute, "eqfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "eqfield") errs = validate.VarWithValue(time.Duration(0), time.Hour, "omitempty,eqfield") Equal(t, errs, nil) // -- Validations for a struct with time.Duration type fields. type TimeDurationTest struct { First time.Duration `validate:"eqfield=Second"` Second time.Duration } var timeDurationTest *TimeDurationTest timeDurationTest = &TimeDurationTest{time.Hour, time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) timeDurationTest = &TimeDurationTest{time.Hour, time.Hour - time.Minute} errs = validate.Struct(timeDurationTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeDurationTest.First", "TimeDurationTest.First", "First", "First", "eqfield") timeDurationTest = &TimeDurationTest{time.Hour, time.Hour + time.Minute} errs = validate.Struct(timeDurationTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeDurationTest.First", "TimeDurationTest.First", "First", "First", "eqfield") type TimeDurationOmitemptyTest struct { First time.Duration `validate:"omitempty,eqfield=Second"` Second time.Duration } timeDurationOmitemptyTest := &TimeDurationOmitemptyTest{time.Duration(0), time.Hour} errs = validate.Struct(timeDurationOmitemptyTest) Equal(t, errs, nil) } func TestIsEqValidation(t *testing.T) { var errs error validate := New() var j uint64 var k float64 s := "abcd" i := 1 j = 1 k = 1.543 arr := []string{"test"} now := time.Now().UTC() errs = validate.Var(s, "eq=abcd") Equal(t, errs, nil) errs = validate.Var(i, "eq=1") Equal(t, errs, nil) errs = validate.Var(j, "eq=1") Equal(t, errs, nil) errs = validate.Var(k, "eq=1.543") Equal(t, errs, nil) errs = validate.Var(arr, "eq=1") Equal(t, errs, nil) errs = validate.Var(arr, "eq=2") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "eq") PanicMatches(t, func() { _ = validate.Var(now, "eq=now") }, "Bad field type time.Time") // Tests for time.Duration type. // -- Validations for a variable of time.Duration type. errs = validate.Var(time.Hour, "eq=1h") Equal(t, errs, nil) errs = validate.Var(time.Hour-time.Minute, "eq=1h") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "eq") errs = validate.Var(time.Hour+time.Minute, "eq=1h") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "eq") errs = validate.Var(time.Duration(0), "omitempty,eq=1h") Equal(t, errs, nil) // -- Validations for a struct with a time.Duration type field. type TimeDurationTest struct { Duration time.Duration `validate:"eq=1h"` } var timeDurationTest *TimeDurationTest timeDurationTest = &TimeDurationTest{time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) timeDurationTest = &TimeDurationTest{time.Hour - time.Minute} errs = validate.Struct(timeDurationTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeDurationTest.Duration", "TimeDurationTest.Duration", "Duration", "Duration", "eq") timeDurationTest = &TimeDurationTest{time.Hour + time.Minute} errs = validate.Struct(timeDurationTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeDurationTest.Duration", "TimeDurationTest.Duration", "Duration", "Duration", "eq") type TimeDurationOmitemptyTest struct { Duration time.Duration `validate:"omitempty,eq=1h"` } timeDurationOmitemptyTest := &TimeDurationOmitemptyTest{time.Duration(0)} errs = validate.Struct(timeDurationOmitemptyTest) Equal(t, errs, nil) } func TestOneOfValidation(t *testing.T) { validate := New() passSpecs := []struct { f interface{} t string }{ {f: "red", t: "oneof=red green"}, {f: "green", t: "oneof=red green"}, {f: "red green", t: "oneof='red green' blue"}, {f: "blue", t: "oneof='red green' blue"}, {f: 5, t: "oneof=5 6"}, {f: 6, t: "oneof=5 6"}, {f: int8(6), t: "oneof=5 6"}, {f: int16(6), t: "oneof=5 6"}, {f: int32(6), t: "oneof=5 6"}, {f: int64(6), t: "oneof=5 6"}, {f: uint(6), t: "oneof=5 6"}, {f: uint8(6), t: "oneof=5 6"}, {f: uint16(6), t: "oneof=5 6"}, {f: uint32(6), t: "oneof=5 6"}, {f: uint64(6), t: "oneof=5 6"}, } for _, spec := range passSpecs { t.Logf("%#v", spec) errs := validate.Var(spec.f, spec.t) Equal(t, errs, nil) } failSpecs := []struct { f interface{} t string }{ {f: "", t: "oneof=red green"}, {f: "yellow", t: "oneof=red green"}, {f: "green", t: "oneof='red green' blue"}, {f: 5, t: "oneof=red green"}, {f: 6, t: "oneof=red green"}, {f: 6, t: "oneof=7"}, {f: uint(6), t: "oneof=7"}, {f: int8(5), t: "oneof=red green"}, {f: int16(5), t: "oneof=red green"}, {f: int32(5), t: "oneof=red green"}, {f: int64(5), t: "oneof=red green"}, {f: uint(5), t: "oneof=red green"}, {f: uint8(5), t: "oneof=red green"}, {f: uint16(5), t: "oneof=red green"}, {f: uint32(5), t: "oneof=red green"}, {f: uint64(5), t: "oneof=red green"}, } for _, spec := range failSpecs { t.Logf("%#v", spec) errs := validate.Var(spec.f, spec.t) AssertError(t, errs, "", "", "", "", "oneof") } PanicMatches(t, func() { _ = validate.Var(3.14, "oneof=red green") }, "Bad field type float64") } func TestBase64Validation(t *testing.T) { validate := New() s := "dW5pY29ybg==" errs := validate.Var(s, "base64") Equal(t, errs, nil) s = "dGhpIGlzIGEgdGVzdCBiYXNlNjQ=" errs = validate.Var(s, "base64") Equal(t, errs, nil) s = "" errs = validate.Var(s, "base64") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "base64") s = "dW5pY29ybg== foo bar" errs = validate.Var(s, "base64") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "base64") } func TestBase64URLValidation(t *testing.T) { validate := New() testCases := []struct { decoded, encoded string success bool }{ // empty string, although a valid base64 string, should fail {"", "", false}, // invalid length {"", "a", false}, // base64 with padding {"f", "Zg==", true}, {"fo", "Zm8=", true}, // base64 without padding {"foo", "Zm9v", true}, {"", "Zg", false}, {"", "Zm8", false}, // base64 URL safe encoding with invalid, special characters '+' and '/' {"\x14\xfb\x9c\x03\xd9\x7e", "FPucA9l+", false}, {"\x14\xfb\x9c\x03\xf9\x73", "FPucA/lz", false}, // base64 URL safe encoding with valid, special characters '-' and '_' {"\x14\xfb\x9c\x03\xd9\x7e", "FPucA9l-", true}, {"\x14\xfb\x9c\x03\xf9\x73", "FPucA_lz", true}, // non base64 characters {"", "@mc=", false}, {"", "Zm 9", false}, } for _, tc := range testCases { err := validate.Var(tc.encoded, "base64url") if tc.success { Equal(t, err, nil) // make sure encoded value is decoded back to the expected value d, innerErr := base64.URLEncoding.DecodeString(tc.encoded) Equal(t, innerErr, nil) Equal(t, tc.decoded, string(d)) } else { NotEqual(t, err, nil) if len(tc.encoded) > 0 { // make sure that indeed the encoded value was faulty _, err := base64.URLEncoding.DecodeString(tc.encoded) NotEqual(t, err, nil) } } } } func TestFileValidation(t *testing.T) { validate := New() tests := []struct { title string param string expected bool }{ {"empty path", "", false}, {"regular file", filepath.Join("testdata", "a.go"), true}, {"missing file", filepath.Join("testdata", "no.go"), false}, {"directory, not a file", "testdata", false}, } for _, test := range tests { errs := validate.Var(test.param, "file") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Test: '%s' failed Error: %s", test.title, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Test: '%s' failed Error: %s", test.title, errs) } } } PanicMatches(t, func() { _ = validate.Var(6, "file") }, "Bad field type int") } func TestEthereumAddressValidation(t *testing.T) { validate := New() tests := []struct { param string expected bool }{ // All caps. {"0x52908400098527886E0F7030069857D2E4169EE7", true}, {"0x8617E340B3D01FA5F11F306F4090FD50E238070D", true}, // All lower. {"0xde709f2102306220921060314715629080e2fb77", true}, {"0x27b1fdb04752bbc536007a920d24acb045561c26", true}, {"0x123f681646d4a755815f9cb19e1acc8565a0c2ac", true}, // Mixed case: runs checksum validation. {"0x02F9AE5f22EA3fA88F05780B30385bECFacbf130", true}, {"0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed", true}, {"0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359", true}, {"0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB", true}, {"0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb", true}, {"0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDB", false}, // Invalid checksum. // Other. {"", false}, {"D1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb", false}, // Missing "0x" prefix. {"0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDbc", false}, // More than 40 hex digits. {"0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aD", false}, // Less than 40 hex digits. {"0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDw", false}, // Invalid hex digit "w". } for i, test := range tests { errs := validate.Var(test.param, "eth_addr") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d eth_addr failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d eth_addr failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "eth_addr" { t.Fatalf("Index: %d Latitude failed Error: %s", i, errs) } } } } } func TestBitcoinAddressValidation(t *testing.T) { validate := New() tests := []struct { param string expected bool }{ {"", false}, {"x", false}, {"0x02F9AE5f22EA3fA88F05780B30385bEC", false}, {"1A1zP1ePQGefi2DMPTifTL5SLmv7DivfNa", false}, {"1P9RQEr2XeE3PEb44ZE35sfZRRW1JH8Uqx", false}, {"3P14159I73E4gFr7JterCCQh9QjiTjiZrG", false}, {"3P141597f3E4gFr7JterCCQh9QjiTjiZrG", false}, {"37qgekLpCCHrQuSjvX3fs496FWTGsHFHizjJAs6NPcR47aefnnCWECAhHV6E3g4YN7u7Yuwod5Y", false}, {"dzb7VV1Ui55BARxv7ATxAtCUeJsANKovDGWFVgpTbhq9gvPqP3yv", false}, {"MuNu7ZAEDFiHthiunm7dPjwKqrVNCM3mAz6rP9zFveQu14YA8CxExSJTHcVP9DErn6u84E6Ej7S", false}, {"rPpQpYknyNQ5AEHuY6H8ijJJrYc2nDKKk9jjmKEXsWzyAQcFGpDLU2Zvsmoi8JLR7hAwoy3RQWf", false}, {"4Uc3FmN6NQ6zLBK5QQBXRBUREaaHwCZYsGCueHauuDmJpZKn6jkEskMB2Zi2CNgtb5r6epWEFfUJq", false}, {"7aQgR5DFQ25vyXmqZAWmnVCjL3PkBcdVkBUpjrjMTcghHx3E8wb", false}, {"17QpPprjeg69fW1DV8DcYYCKvWjYhXvWkov6MJ1iTTvMFj6weAqW7wybZeH57WTNxXVCRH4veVs", false}, {"KxuACDviz8Xvpn1xAh9MfopySZNuyajYMZWz16Dv2mHHryznWUp3", false}, {"7nK3GSmqdXJQtdohvGfJ7KsSmn3TmGqExug49583bDAL91pVSGq5xS9SHoAYL3Wv3ijKTit65th", false}, {"cTivdBmq7bay3RFGEBBuNfMh2P1pDCgRYN2Wbxmgwr4ki3jNUL2va", false}, {"gjMV4vjNjyMrna4fsAr8bWxAbwtmMUBXJS3zL4NJt5qjozpbQLmAfK1uA3CquSqsZQMpoD1g2nk", false}, {"emXm1naBMoVzPjbk7xpeTVMFy4oDEe25UmoyGgKEB1gGWsK8kRGs", false}, {"7VThQnNRj1o3Zyvc7XHPRrjDf8j2oivPTeDXnRPYWeYGE4pXeRJDZgf28ppti5hsHWXS2GSobdqyo", false}, {"1G9u6oCVCPh2o8m3t55ACiYvG1y5BHewUkDSdiQarDcYXXhFHYdzMdYfUAhfxn5vNZBwpgUNpso", false}, {"31QQ7ZMLkScDiB4VyZjuptr7AEc9j1SjstF7pRoLhHTGkW4Q2y9XELobQmhhWxeRvqcukGd1XCq", false}, {"DHqKSnpxa8ZdQyH8keAhvLTrfkyBMQxqngcQA5N8LQ9KVt25kmGN", false}, {"2LUHcJPbwLCy9GLH1qXmfmAwvadWw4bp4PCpDfduLqV17s6iDcy1imUwhQJhAoNoN1XNmweiJP4i", false}, {"7USRzBXAnmck8fX9HmW7RAb4qt92VFX6soCnts9s74wxm4gguVhtG5of8fZGbNPJA83irHVY6bCos", false}, {"1DGezo7BfVebZxAbNT3XGujdeHyNNBF3vnficYoTSp4PfK2QaML9bHzAMxke3wdKdHYWmsMTJVu", false}, {"2D12DqDZKwCxxkzs1ZATJWvgJGhQ4cFi3WrizQ5zLAyhN5HxuAJ1yMYaJp8GuYsTLLxTAz6otCfb", false}, {"8AFJzuTujXjw1Z6M3fWhQ1ujDW7zsV4ePeVjVo7D1egERqSW9nZ", false}, {"163Q17qLbTCue8YY3AvjpUhotuaodLm2uqMhpYirsKjVqnxJRWTEoywMVY3NbBAHuhAJ2cF9GAZ", false}, {"2MnmgiRH4eGLyLc9eAqStzk7dFgBjFtUCtu", false}, {"461QQ2sYWxU7H2PV4oBwJGNch8XVTYYbZxU", false}, {"2UCtv53VttmQYkVU4VMtXB31REvQg4ABzs41AEKZ8UcB7DAfVzdkV9JDErwGwyj5AUHLkmgZeobs", false}, {"cSNjAsnhgtiFMi6MtfvgscMB2Cbhn2v1FUYfviJ1CdjfidvmeW6mn", false}, {"gmsow2Y6EWAFDFE1CE4Hd3Tpu2BvfmBfG1SXsuRARbnt1WjkZnFh1qGTiptWWbjsq2Q6qvpgJVj", false}, {"nksUKSkzS76v8EsSgozXGMoQFiCoCHzCVajFKAXqzK5on9ZJYVHMD5CKwgmX3S3c7M1U3xabUny", false}, {"L3favK1UzFGgdzYBF2oBT5tbayCo4vtVBLJhg2iYuMeePxWG8SQc", false}, {"7VxLxGGtYT6N99GdEfi6xz56xdQ8nP2dG1CavuXx7Rf2PrvNMTBNevjkfgs9JmkcGm6EXpj8ipyPZ ", false}, {"2mbZwFXF6cxShaCo2czTRB62WTx9LxhTtpP", false}, {"dB7cwYdcPSgiyAwKWL3JwCVwSk6epU2txw", false}, {"HPhFUhUAh8ZQQisH8QQWafAxtQYju3SFTX", false}, {"4ctAH6AkHzq5ioiM1m9T3E2hiYEev5mTsB", false}, {"31uEbMgunupShBVTewXjtqbBv5MndwfXhb", false}, {"175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W", false}, {"Hn1uFi4dNexWrqARpjMqgT6cX1UsNPuV3cHdGg9ExyXw8HTKadbktRDtdeVmY3M1BxJStiL4vjJ", false}, {"Sq3fDbvutABmnAHHExJDgPLQn44KnNC7UsXuT7KZecpaYDMU9Txs", false}, {"6TqWyrqdgUEYDQU1aChMuFMMEimHX44qHFzCUgGfqxGgZNMUVWJ", false}, {"giqJo7oWqFxNKWyrgcBxAVHXnjJ1t6cGoEffce5Y1y7u649Noj5wJ4mmiUAKEVVrYAGg2KPB3Y4", false}, {"cNzHY5e8vcmM3QVJUcjCyiKMYfeYvyueq5qCMV3kqcySoLyGLYUK", false}, {"37uTe568EYc9WLoHEd9jXEvUiWbq5LFLscNyqvAzLU5vBArUJA6eydkLmnMwJDjkL5kXc2VK7ig", false}, {"EsYbG4tWWWY45G31nox838qNdzksbPySWc", false}, {"nbuzhfwMoNzA3PaFnyLcRxE9bTJPDkjZ6Rf6Y6o2ckXZfzZzXBT", false}, {"cQN9PoxZeCWK1x56xnz6QYAsvR11XAce3Ehp3gMUdfSQ53Y2mPzx", false}, {"1Gm3N3rkef6iMbx4voBzaxtXcmmiMTqZPhcuAepRzYUJQW4qRpEnHvMojzof42hjFRf8PE2jPde", false}, {"2TAq2tuN6x6m233bpT7yqdYQPELdTDJn1eU", false}, {"ntEtnnGhqPii4joABvBtSEJG6BxjT2tUZqE8PcVYgk3RHpgxgHDCQxNbLJf7ardf1dDk2oCQ7Cf", false}, {"Ky1YjoZNgQ196HJV3HpdkecfhRBmRZdMJk89Hi5KGfpfPwS2bUbfd", false}, {"2A1q1YsMZowabbvta7kTy2Fd6qN4r5ZCeG3qLpvZBMzCixMUdkN2Y4dHB1wPsZAeVXUGD83MfRED", false}, {"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", true}, {"1Ax4gZtb7gAit2TivwejZHYtNNLT18PUXJ", true}, {"1C5bSj1iEGUgSTbziymG7Cn18ENQuT36vv", true}, {"1Gqk4Tv79P91Cc1STQtU3s1W6277M2CVWu", true}, {"1JwMWBVLtiqtscbaRHai4pqHokhFCbtoB4", true}, {"19dcawoKcZdQz365WpXWMhX6QCUpR9SY4r", true}, {"13p1ijLwsnrcuyqcTvJXkq2ASdXqcnEBLE", true}, {"1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2", true}, {"3P14159f73E4gFr7JterCCQh9QjiTjiZrG", true}, {"3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou", true}, {"3QjYXhTkvuj8qPaXHTTWb5wjXhdsLAAWVy", true}, {"3AnNxabYGoTxYiTEZwFEnerUoeFXK2Zoks", true}, {"33vt8ViH5jsr115AGkW6cEmEz9MpvJSwDk", true}, {"3QCzvfL4ZRvmJFiWWBVwxfdaNBT8EtxB5y", true}, {"37Sp6Rv3y4kVd1nQ1JV5pfqXccHNyZm1x3", true}, {"3ALJH9Y951VCGcVZYAdpA3KchoP9McEj1G", true}, {"12KYrjTdVGjFMtaxERSk3gphreJ5US8aUP", true}, {"12QeMLzSrB8XH8FvEzPMVoRxVAzTr5XM2y", true}, {"1oNLrsHnBcR6dpaBpwz3LSwutbUNkNSjs", true}, {"1SQHtwR5oJRKLfiWQ2APsAd9miUc4k2ez", true}, {"116CGDLddrZhMrTwhCVJXtXQpxygTT1kHd", true}, {"3NJZLcZEEYBpxYEUGewU4knsQRn1WM5Fkt", true}, } for i, test := range tests { errs := validate.Var(test.param, "btc_addr") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d btc_addr failed with Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d btc_addr failed with Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "btc_addr" { t.Fatalf("Index: %d Latitude failed with Error: %s", i, errs) } } } } } func TestBitcoinBech32AddressValidation(t *testing.T) { validate := New() tests := []struct { param string expected bool }{ {"", false}, {"bc1rw5uspcuh", false}, {"bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5", false}, {"BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2", false}, {"qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty", false}, {"bc1rw5uspcuh", false}, {"bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90", false}, {"BC1QW508d6QEJxTDG4y5R3ZArVARY0C5XW7KV8F3T4", false}, {"BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P", false}, {"bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5", false}, {"bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90", false}, {"bc1pw508d6qejxtdg4y5r3zarqfsj6c3", false}, {"bc1zw508d6qejxtdg4y5r3zarvaryvqyzf3du", false}, {"bc1gmk9yu", false}, {"bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv", false}, {"BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4", true}, {"bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx", true}, {"bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3", true}, {"BC1SW50QA3JX3S", true}, {"bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj", true}, } for i, test := range tests { errs := validate.Var(test.param, "btc_addr_bech32") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d btc_addr_bech32 failed with Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d btc_addr_bech32 failed with Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "btc_addr_bech32" { t.Fatalf("Index: %d Latitude failed with Error: %s", i, errs) } } } } } func TestNoStructLevelValidation(t *testing.T) { type Inner struct { Test string `validate:"len=5"` } type Outer struct { InnerStruct *Inner `validate:"required,nostructlevel"` } outer := &Outer{ InnerStruct: nil, } validate := New() errs := validate.Struct(outer) NotEqual(t, errs, nil) AssertError(t, errs, "Outer.InnerStruct", "Outer.InnerStruct", "InnerStruct", "InnerStruct", "required") inner := &Inner{ Test: "1234", } outer = &Outer{ InnerStruct: inner, } errs = validate.Struct(outer) Equal(t, errs, nil) } func TestStructOnlyValidation(t *testing.T) { type Inner struct { Test string `validate:"len=5"` } type Outer struct { InnerStruct *Inner `validate:"required,structonly"` } outer := &Outer{ InnerStruct: nil, } validate := New() errs := validate.Struct(outer) NotEqual(t, errs, nil) AssertError(t, errs, "Outer.InnerStruct", "Outer.InnerStruct", "InnerStruct", "InnerStruct", "required") inner := &Inner{ Test: "1234", } outer = &Outer{ InnerStruct: inner, } errs = validate.Struct(outer) Equal(t, errs, nil) // Address houses a users address information type Address struct { Street string `validate:"required"` City string `validate:"required"` Planet string `validate:"required"` Phone string `validate:"required"` } type User struct { FirstName string `json:"fname"` LastName string `json:"lname"` Age uint8 `validate:"gte=0,lte=130"` Number string `validate:"required,e164"` Email string `validate:"required,email"` FavouriteColor string `validate:"hexcolor|rgb|rgba"` Addresses []*Address `validate:"required"` // a person can have a home and cottage... Address Address `validate:"structonly"` // a person can have a home and cottage... } address := &Address{ Street: "Eavesdown Docks", Planet: "Persphone", Phone: "none", City: "Unknown", } user := &User{ FirstName: "", LastName: "", Age: 45, Number: "+1123456789", Email: "Badger.Smith@gmail.com", FavouriteColor: "#000", Addresses: []*Address{address}, Address: Address{ // Street: "Eavesdown Docks", Planet: "Persphone", Phone: "none", City: "Unknown", }, } errs = validate.Struct(user) Equal(t, errs, nil) } func TestGtField(t *testing.T) { var errs error validate := New() type TimeTest struct { Start *time.Time `validate:"required,gt"` End *time.Time `validate:"required,gt,gtfield=Start"` } now := time.Now() start := now.Add(time.Hour * 24) end := start.Add(time.Hour * 24) timeTest := &TimeTest{ Start: &start, End: &end, } errs = validate.Struct(timeTest) Equal(t, errs, nil) timeTest = &TimeTest{ Start: &end, End: &start, } errs = validate.Struct(timeTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeTest.End", "TimeTest.End", "End", "End", "gtfield") errs = validate.VarWithValue(&end, &start, "gtfield") Equal(t, errs, nil) errs = validate.VarWithValue(&start, &end, "gtfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "gtfield") errs = validate.VarWithValue(&end, &start, "gtfield") Equal(t, errs, nil) errs = validate.VarWithValue(&timeTest, &end, "gtfield") NotEqual(t, errs, nil) errs = validate.VarWithValue("test bigger", "test", "gtfield") Equal(t, errs, nil) // Tests for time.Duration type. // -- Validations for variables of time.Duration type. errs = validate.VarWithValue(time.Hour, time.Hour-time.Minute, "gtfield") Equal(t, errs, nil) errs = validate.VarWithValue(time.Hour, time.Hour, "gtfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "gtfield") errs = validate.VarWithValue(time.Hour, time.Hour+time.Minute, "gtfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "gtfield") errs = validate.VarWithValue(time.Duration(0), time.Hour, "omitempty,gtfield") Equal(t, errs, nil) // -- Validations for a struct with time.Duration type fields. type TimeDurationTest struct { First time.Duration `validate:"gtfield=Second"` Second time.Duration } var timeDurationTest *TimeDurationTest timeDurationTest = &TimeDurationTest{time.Hour, time.Hour - time.Minute} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) timeDurationTest = &TimeDurationTest{time.Hour, time.Hour} errs = validate.Struct(timeDurationTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeDurationTest.First", "TimeDurationTest.First", "First", "First", "gtfield") timeDurationTest = &TimeDurationTest{time.Hour, time.Hour + time.Minute} errs = validate.Struct(timeDurationTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeDurationTest.First", "TimeDurationTest.First", "First", "First", "gtfield") type TimeDurationOmitemptyTest struct { First time.Duration `validate:"omitempty,gtfield=Second"` Second time.Duration } timeDurationOmitemptyTest := &TimeDurationOmitemptyTest{time.Duration(0), time.Hour} errs = validate.Struct(timeDurationOmitemptyTest) Equal(t, errs, nil) // Tests for Ints types. type IntTest struct { Val1 int `validate:"required"` Val2 int `validate:"required,gtfield=Val1"` } intTest := &IntTest{ Val1: 1, Val2: 5, } errs = validate.Struct(intTest) Equal(t, errs, nil) intTest = &IntTest{ Val1: 5, Val2: 1, } errs = validate.Struct(intTest) NotEqual(t, errs, nil) AssertError(t, errs, "IntTest.Val2", "IntTest.Val2", "Val2", "Val2", "gtfield") errs = validate.VarWithValue(int(5), int(1), "gtfield") Equal(t, errs, nil) errs = validate.VarWithValue(int(1), int(5), "gtfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "gtfield") type UIntTest struct { Val1 uint `validate:"required"` Val2 uint `validate:"required,gtfield=Val1"` } uIntTest := &UIntTest{ Val1: 1, Val2: 5, } errs = validate.Struct(uIntTest) Equal(t, errs, nil) uIntTest = &UIntTest{ Val1: 5, Val2: 1, } errs = validate.Struct(uIntTest) NotEqual(t, errs, nil) AssertError(t, errs, "UIntTest.Val2", "UIntTest.Val2", "Val2", "Val2", "gtfield") errs = validate.VarWithValue(uint(5), uint(1), "gtfield") Equal(t, errs, nil) errs = validate.VarWithValue(uint(1), uint(5), "gtfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "gtfield") type FloatTest struct { Val1 float64 `validate:"required"` Val2 float64 `validate:"required,gtfield=Val1"` } floatTest := &FloatTest{ Val1: 1, Val2: 5, } errs = validate.Struct(floatTest) Equal(t, errs, nil) floatTest = &FloatTest{ Val1: 5, Val2: 1, } errs = validate.Struct(floatTest) NotEqual(t, errs, nil) AssertError(t, errs, "FloatTest.Val2", "FloatTest.Val2", "Val2", "Val2", "gtfield") errs = validate.VarWithValue(float32(5), float32(1), "gtfield") Equal(t, errs, nil) errs = validate.VarWithValue(float32(1), float32(5), "gtfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "gtfield") errs = validate.VarWithValue(nil, 1, "gtfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "gtfield") errs = validate.VarWithValue(5, "T", "gtfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "gtfield") errs = validate.VarWithValue(5, start, "gtfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "gtfield") type TimeTest2 struct { Start *time.Time `validate:"required"` End *time.Time `validate:"required,gtfield=NonExistantField"` } timeTest2 := &TimeTest2{ Start: &start, End: &end, } errs = validate.Struct(timeTest2) NotEqual(t, errs, nil) AssertError(t, errs, "TimeTest2.End", "TimeTest2.End", "End", "End", "gtfield") type Other struct { Value string } type Test struct { Value Other Time time.Time `validate:"gtfield=Value"` } tst := Test{ Value: Other{Value: "StringVal"}, Time: end, } errs = validate.Struct(tst) NotEqual(t, errs, nil) AssertError(t, errs, "Test.Time", "Test.Time", "Time", "Time", "gtfield") } func TestLtField(t *testing.T) { var errs error validate := New() type TimeTest struct { Start *time.Time `validate:"required,lt,ltfield=End"` End *time.Time `validate:"required,lt"` } now := time.Now() start := now.Add(time.Hour * 24 * -1 * 2) end := start.Add(time.Hour * 24) timeTest := &TimeTest{ Start: &start, End: &end, } errs = validate.Struct(timeTest) Equal(t, errs, nil) timeTest = &TimeTest{ Start: &end, End: &start, } errs = validate.Struct(timeTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeTest.Start", "TimeTest.Start", "Start", "Start", "ltfield") errs = validate.VarWithValue(&start, &end, "ltfield") Equal(t, errs, nil) errs = validate.VarWithValue(&end, &start, "ltfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "ltfield") errs = validate.VarWithValue(&end, timeTest, "ltfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "ltfield") errs = validate.VarWithValue("tes", "test", "ltfield") Equal(t, errs, nil) // Tests for time.Duration type. // -- Validations for variables of time.Duration type. errs = validate.VarWithValue(time.Hour, time.Hour+time.Minute, "ltfield") Equal(t, errs, nil) errs = validate.VarWithValue(time.Hour, time.Hour, "ltfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "ltfield") errs = validate.VarWithValue(time.Hour, time.Hour-time.Minute, "ltfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "ltfield") errs = validate.VarWithValue(time.Duration(0), -time.Minute, "omitempty,ltfield") Equal(t, errs, nil) // -- Validations for a struct with time.Duration type fields. type TimeDurationTest struct { First time.Duration `validate:"ltfield=Second"` Second time.Duration } var timeDurationTest *TimeDurationTest timeDurationTest = &TimeDurationTest{time.Hour, time.Hour + time.Minute} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) timeDurationTest = &TimeDurationTest{time.Hour, time.Hour} errs = validate.Struct(timeDurationTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeDurationTest.First", "TimeDurationTest.First", "First", "First", "ltfield") timeDurationTest = &TimeDurationTest{time.Hour, time.Hour - time.Minute} errs = validate.Struct(timeDurationTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeDurationTest.First", "TimeDurationTest.First", "First", "First", "ltfield") type TimeDurationOmitemptyTest struct { First time.Duration `validate:"omitempty,ltfield=Second"` Second time.Duration } timeDurationOmitemptyTest := &TimeDurationOmitemptyTest{time.Duration(0), -time.Minute} errs = validate.Struct(timeDurationOmitemptyTest) Equal(t, errs, nil) // Tests for Ints types. type IntTest struct { Val1 int `validate:"required"` Val2 int `validate:"required,ltfield=Val1"` } intTest := &IntTest{ Val1: 5, Val2: 1, } errs = validate.Struct(intTest) Equal(t, errs, nil) intTest = &IntTest{ Val1: 1, Val2: 5, } errs = validate.Struct(intTest) NotEqual(t, errs, nil) AssertError(t, errs, "IntTest.Val2", "IntTest.Val2", "Val2", "Val2", "ltfield") errs = validate.VarWithValue(int(1), int(5), "ltfield") Equal(t, errs, nil) errs = validate.VarWithValue(int(5), int(1), "ltfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "ltfield") type UIntTest struct { Val1 uint `validate:"required"` Val2 uint `validate:"required,ltfield=Val1"` } uIntTest := &UIntTest{ Val1: 5, Val2: 1, } errs = validate.Struct(uIntTest) Equal(t, errs, nil) uIntTest = &UIntTest{ Val1: 1, Val2: 5, } errs = validate.Struct(uIntTest) NotEqual(t, errs, nil) AssertError(t, errs, "UIntTest.Val2", "UIntTest.Val2", "Val2", "Val2", "ltfield") errs = validate.VarWithValue(uint(1), uint(5), "ltfield") Equal(t, errs, nil) errs = validate.VarWithValue(uint(5), uint(1), "ltfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "ltfield") type FloatTest struct { Val1 float64 `validate:"required"` Val2 float64 `validate:"required,ltfield=Val1"` } floatTest := &FloatTest{ Val1: 5, Val2: 1, } errs = validate.Struct(floatTest) Equal(t, errs, nil) floatTest = &FloatTest{ Val1: 1, Val2: 5, } errs = validate.Struct(floatTest) NotEqual(t, errs, nil) AssertError(t, errs, "FloatTest.Val2", "FloatTest.Val2", "Val2", "Val2", "ltfield") errs = validate.VarWithValue(float32(1), float32(5), "ltfield") Equal(t, errs, nil) errs = validate.VarWithValue(float32(5), float32(1), "ltfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "ltfield") errs = validate.VarWithValue(nil, 5, "ltfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "ltfield") errs = validate.VarWithValue(1, "T", "ltfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "ltfield") errs = validate.VarWithValue(1, end, "ltfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "ltfield") type TimeTest2 struct { Start *time.Time `validate:"required"` End *time.Time `validate:"required,ltfield=NonExistantField"` } timeTest2 := &TimeTest2{ Start: &end, End: &start, } errs = validate.Struct(timeTest2) NotEqual(t, errs, nil) AssertError(t, errs, "TimeTest2.End", "TimeTest2.End", "End", "End", "ltfield") } func TestFieldContains(t *testing.T) { validate := New() type StringTest struct { Foo string `validate:"fieldcontains=Bar"` Bar string } stringTest := &StringTest{ Foo: "foobar", Bar: "bar", } errs := validate.Struct(stringTest) Equal(t, errs, nil) stringTest = &StringTest{ Foo: "foo", Bar: "bar", } errs = validate.Struct(stringTest) NotEqual(t, errs, nil) AssertError(t, errs, "StringTest.Foo", "StringTest.Foo", "Foo", "Foo", "fieldcontains") errs = validate.VarWithValue("foo", "bar", "fieldcontains") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "fieldcontains") errs = validate.VarWithValue("bar", "foobarfoo", "fieldcontains") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "fieldcontains") errs = validate.VarWithValue("foobarfoo", "bar", "fieldcontains") Equal(t, errs, nil) type StringTestMissingField struct { Foo string `validate:"fieldcontains=Bar"` } stringTestMissingField := &StringTestMissingField{ Foo: "foo", } errs = validate.Struct(stringTestMissingField) NotEqual(t, errs, nil) AssertError(t, errs, "StringTestMissingField.Foo", "StringTestMissingField.Foo", "Foo", "Foo", "fieldcontains") } func TestFieldExcludes(t *testing.T) { validate := New() type StringTest struct { Foo string `validate:"fieldexcludes=Bar"` Bar string } stringTest := &StringTest{ Foo: "foobar", Bar: "bar", } errs := validate.Struct(stringTest) NotEqual(t, errs, nil) AssertError(t, errs, "StringTest.Foo", "StringTest.Foo", "Foo", "Foo", "fieldexcludes") stringTest = &StringTest{ Foo: "foo", Bar: "bar", } errs = validate.Struct(stringTest) Equal(t, errs, nil) errs = validate.VarWithValue("foo", "bar", "fieldexcludes") Equal(t, errs, nil) errs = validate.VarWithValue("bar", "foobarfoo", "fieldexcludes") Equal(t, errs, nil) errs = validate.VarWithValue("foobarfoo", "bar", "fieldexcludes") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "fieldexcludes") type StringTestMissingField struct { Foo string `validate:"fieldexcludes=Bar"` } stringTestMissingField := &StringTestMissingField{ Foo: "foo", } errs = validate.Struct(stringTestMissingField) Equal(t, errs, nil) } func TestContainsAndExcludes(t *testing.T) { validate := New() type ImpossibleStringTest struct { Foo string `validate:"fieldcontains=Bar"` Bar string `validate:"fieldexcludes=Foo"` } impossibleStringTest := &ImpossibleStringTest{ Foo: "foo", Bar: "bar", } errs := validate.Struct(impossibleStringTest) NotEqual(t, errs, nil) AssertError(t, errs, "ImpossibleStringTest.Foo", "ImpossibleStringTest.Foo", "Foo", "Foo", "fieldcontains") impossibleStringTest = &ImpossibleStringTest{ Foo: "bar", Bar: "foo", } errs = validate.Struct(impossibleStringTest) NotEqual(t, errs, nil) AssertError(t, errs, "ImpossibleStringTest.Foo", "ImpossibleStringTest.Foo", "Foo", "Foo", "fieldcontains") } func TestLteField(t *testing.T) { var errs error validate := New() type TimeTest struct { Start *time.Time `validate:"required,lte,ltefield=End"` End *time.Time `validate:"required,lte"` } now := time.Now() start := now.Add(time.Hour * 24 * -1 * 2) end := start.Add(time.Hour * 24) timeTest := &TimeTest{ Start: &start, End: &end, } errs = validate.Struct(timeTest) Equal(t, errs, nil) timeTest = &TimeTest{ Start: &end, End: &start, } errs = validate.Struct(timeTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeTest.Start", "TimeTest.Start", "Start", "Start", "ltefield") errs = validate.VarWithValue(&start, &end, "ltefield") Equal(t, errs, nil) errs = validate.VarWithValue(&end, &start, "ltefield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "ltefield") errs = validate.VarWithValue(&end, timeTest, "ltefield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "ltefield") errs = validate.VarWithValue("tes", "test", "ltefield") Equal(t, errs, nil) errs = validate.VarWithValue("test", "test", "ltefield") Equal(t, errs, nil) // Tests for time.Duration type. // -- Validations for variables of time.Duration type. errs = validate.VarWithValue(time.Hour, time.Hour+time.Minute, "ltefield") Equal(t, errs, nil) errs = validate.VarWithValue(time.Hour, time.Hour, "ltefield") Equal(t, errs, nil) errs = validate.VarWithValue(time.Hour, time.Hour-time.Minute, "ltefield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "ltefield") errs = validate.VarWithValue(time.Duration(0), -time.Minute, "omitempty,ltefield") Equal(t, errs, nil) // -- Validations for a struct with time.Duration type fields. type TimeDurationTest struct { First time.Duration `validate:"ltefield=Second"` Second time.Duration } var timeDurationTest *TimeDurationTest timeDurationTest = &TimeDurationTest{time.Hour, time.Hour + time.Minute} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) timeDurationTest = &TimeDurationTest{time.Hour, time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) timeDurationTest = &TimeDurationTest{time.Hour, time.Hour - time.Minute} errs = validate.Struct(timeDurationTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeDurationTest.First", "TimeDurationTest.First", "First", "First", "ltefield") type TimeDurationOmitemptyTest struct { First time.Duration `validate:"omitempty,ltefield=Second"` Second time.Duration } timeDurationOmitemptyTest := &TimeDurationOmitemptyTest{time.Duration(0), -time.Minute} errs = validate.Struct(timeDurationOmitemptyTest) Equal(t, errs, nil) // Tests for Ints types. type IntTest struct { Val1 int `validate:"required"` Val2 int `validate:"required,ltefield=Val1"` } intTest := &IntTest{ Val1: 5, Val2: 1, } errs = validate.Struct(intTest) Equal(t, errs, nil) intTest = &IntTest{ Val1: 1, Val2: 5, } errs = validate.Struct(intTest) NotEqual(t, errs, nil) AssertError(t, errs, "IntTest.Val2", "IntTest.Val2", "Val2", "Val2", "ltefield") errs = validate.VarWithValue(int(1), int(5), "ltefield") Equal(t, errs, nil) errs = validate.VarWithValue(int(5), int(1), "ltefield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "ltefield") type UIntTest struct { Val1 uint `validate:"required"` Val2 uint `validate:"required,ltefield=Val1"` } uIntTest := &UIntTest{ Val1: 5, Val2: 1, } errs = validate.Struct(uIntTest) Equal(t, errs, nil) uIntTest = &UIntTest{ Val1: 1, Val2: 5, } errs = validate.Struct(uIntTest) NotEqual(t, errs, nil) AssertError(t, errs, "UIntTest.Val2", "UIntTest.Val2", "Val2", "Val2", "ltefield") errs = validate.VarWithValue(uint(1), uint(5), "ltefield") Equal(t, errs, nil) errs = validate.VarWithValue(uint(5), uint(1), "ltefield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "ltefield") type FloatTest struct { Val1 float64 `validate:"required"` Val2 float64 `validate:"required,ltefield=Val1"` } floatTest := &FloatTest{ Val1: 5, Val2: 1, } errs = validate.Struct(floatTest) Equal(t, errs, nil) floatTest = &FloatTest{ Val1: 1, Val2: 5, } errs = validate.Struct(floatTest) NotEqual(t, errs, nil) AssertError(t, errs, "FloatTest.Val2", "FloatTest.Val2", "Val2", "Val2", "ltefield") errs = validate.VarWithValue(float32(1), float32(5), "ltefield") Equal(t, errs, nil) errs = validate.VarWithValue(float32(5), float32(1), "ltefield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "ltefield") errs = validate.VarWithValue(nil, 5, "ltefield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "ltefield") errs = validate.VarWithValue(1, "T", "ltefield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "ltefield") errs = validate.VarWithValue(1, end, "ltefield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "ltefield") type TimeTest2 struct { Start *time.Time `validate:"required"` End *time.Time `validate:"required,ltefield=NonExistantField"` } timeTest2 := &TimeTest2{ Start: &end, End: &start, } errs = validate.Struct(timeTest2) NotEqual(t, errs, nil) AssertError(t, errs, "TimeTest2.End", "TimeTest2.End", "End", "End", "ltefield") } func TestGteField(t *testing.T) { var errs error validate := New() type TimeTest struct { Start *time.Time `validate:"required,gte"` End *time.Time `validate:"required,gte,gtefield=Start"` } now := time.Now() start := now.Add(time.Hour * 24) end := start.Add(time.Hour * 24) timeTest := &TimeTest{ Start: &start, End: &end, } errs = validate.Struct(timeTest) Equal(t, errs, nil) timeTest = &TimeTest{ Start: &end, End: &start, } errs = validate.Struct(timeTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeTest.End", "TimeTest.End", "End", "End", "gtefield") errs = validate.VarWithValue(&end, &start, "gtefield") Equal(t, errs, nil) errs = validate.VarWithValue(&start, &end, "gtefield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "gtefield") errs = validate.VarWithValue(&start, timeTest, "gtefield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "gtefield") errs = validate.VarWithValue("test", "test", "gtefield") Equal(t, errs, nil) errs = validate.VarWithValue("test bigger", "test", "gtefield") Equal(t, errs, nil) // Tests for time.Duration type. // -- Validations for variables of time.Duration type. errs = validate.VarWithValue(time.Hour, time.Hour-time.Minute, "gtefield") Equal(t, errs, nil) errs = validate.VarWithValue(time.Hour, time.Hour, "gtefield") Equal(t, errs, nil) errs = validate.VarWithValue(time.Hour, time.Hour+time.Minute, "gtefield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "gtefield") errs = validate.VarWithValue(time.Duration(0), time.Hour, "omitempty,gtefield") Equal(t, errs, nil) // -- Validations for a struct with time.Duration type fields. type TimeDurationTest struct { First time.Duration `validate:"gtefield=Second"` Second time.Duration } var timeDurationTest *TimeDurationTest timeDurationTest = &TimeDurationTest{time.Hour, time.Hour - time.Minute} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) timeDurationTest = &TimeDurationTest{time.Hour, time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) timeDurationTest = &TimeDurationTest{time.Hour, time.Hour + time.Minute} errs = validate.Struct(timeDurationTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeDurationTest.First", "TimeDurationTest.First", "First", "First", "gtefield") type TimeDurationOmitemptyTest struct { First time.Duration `validate:"omitempty,gtefield=Second"` Second time.Duration } timeDurationOmitemptyTest := &TimeDurationOmitemptyTest{time.Duration(0), time.Hour} errs = validate.Struct(timeDurationOmitemptyTest) Equal(t, errs, nil) // Tests for Ints types. type IntTest struct { Val1 int `validate:"required"` Val2 int `validate:"required,gtefield=Val1"` } intTest := &IntTest{ Val1: 1, Val2: 5, } errs = validate.Struct(intTest) Equal(t, errs, nil) intTest = &IntTest{ Val1: 5, Val2: 1, } errs = validate.Struct(intTest) NotEqual(t, errs, nil) AssertError(t, errs, "IntTest.Val2", "IntTest.Val2", "Val2", "Val2", "gtefield") errs = validate.VarWithValue(int(5), int(1), "gtefield") Equal(t, errs, nil) errs = validate.VarWithValue(int(1), int(5), "gtefield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "gtefield") type UIntTest struct { Val1 uint `validate:"required"` Val2 uint `validate:"required,gtefield=Val1"` } uIntTest := &UIntTest{ Val1: 1, Val2: 5, } errs = validate.Struct(uIntTest) Equal(t, errs, nil) uIntTest = &UIntTest{ Val1: 5, Val2: 1, } errs = validate.Struct(uIntTest) NotEqual(t, errs, nil) AssertError(t, errs, "UIntTest.Val2", "UIntTest.Val2", "Val2", "Val2", "gtefield") errs = validate.VarWithValue(uint(5), uint(1), "gtefield") Equal(t, errs, nil) errs = validate.VarWithValue(uint(1), uint(5), "gtefield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "gtefield") type FloatTest struct { Val1 float64 `validate:"required"` Val2 float64 `validate:"required,gtefield=Val1"` } floatTest := &FloatTest{ Val1: 1, Val2: 5, } errs = validate.Struct(floatTest) Equal(t, errs, nil) floatTest = &FloatTest{ Val1: 5, Val2: 1, } errs = validate.Struct(floatTest) NotEqual(t, errs, nil) AssertError(t, errs, "FloatTest.Val2", "FloatTest.Val2", "Val2", "Val2", "gtefield") errs = validate.VarWithValue(float32(5), float32(1), "gtefield") Equal(t, errs, nil) errs = validate.VarWithValue(float32(1), float32(5), "gtefield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "gtefield") errs = validate.VarWithValue(nil, 1, "gtefield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "gtefield") errs = validate.VarWithValue(5, "T", "gtefield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "gtefield") errs = validate.VarWithValue(5, start, "gtefield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "gtefield") type TimeTest2 struct { Start *time.Time `validate:"required"` End *time.Time `validate:"required,gtefield=NonExistantField"` } timeTest2 := &TimeTest2{ Start: &start, End: &end, } errs = validate.Struct(timeTest2) NotEqual(t, errs, nil) AssertError(t, errs, "TimeTest2.End", "TimeTest2.End", "End", "End", "gtefield") } func TestValidateByTagAndValue(t *testing.T) { validate := New() val := "test" field := "test" errs := validate.VarWithValue(val, field, "required") Equal(t, errs, nil) fn := func(fl FieldLevel) bool { return fl.Parent().String() == fl.Field().String() } errs = validate.RegisterValidation("isequaltestfunc", fn) Equal(t, errs, nil) errs = validate.VarWithValue(val, field, "isequaltestfunc") Equal(t, errs, nil) val = "unequal" errs = validate.VarWithValue(val, field, "isequaltestfunc") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "isequaltestfunc") } func TestAddFunctions(t *testing.T) { fn := func(fl FieldLevel) bool { return true } fnCtx := func(ctx context.Context, fl FieldLevel) bool { return true } validate := New() errs := validate.RegisterValidation("new", fn) Equal(t, errs, nil) errs = validate.RegisterValidation("", fn) NotEqual(t, errs, nil) errs = validate.RegisterValidation("new", nil) NotEqual(t, errs, nil) errs = validate.RegisterValidation("new", fn) Equal(t, errs, nil) errs = validate.RegisterValidationCtx("new", fnCtx) Equal(t, errs, nil) PanicMatches(t, func() { _ = validate.RegisterValidation("dive", fn) }, "Tag 'dive' either contains restricted characters or is the same as a restricted tag needed for normal operation") } func TestChangeTag(t *testing.T) { validate := New() validate.SetTagName("val") type Test struct { Name string `val:"len=4"` } s := &Test{ Name: "TEST", } errs := validate.Struct(s) Equal(t, errs, nil) s.Name = "" errs = validate.Struct(s) NotEqual(t, errs, nil) AssertError(t, errs, "Test.Name", "Test.Name", "Name", "Name", "len") } func TestUnexposedStruct(t *testing.T) { validate := New() type Test struct { Name string unexposed struct { A string `validate:"required"` } } s := &Test{ Name: "TEST", } Equal(t, s.unexposed.A, "") errs := validate.Struct(s) Equal(t, errs, nil) } func TestBadParams(t *testing.T) { validate := New() i := 1 errs := validate.Var(i, "-") Equal(t, errs, nil) PanicMatches(t, func() { _ = validate.Var(i, "len=a") }, "strconv.ParseInt: parsing \"a\": invalid syntax") PanicMatches(t, func() { _ = validate.Var(i, "len=a") }, "strconv.ParseInt: parsing \"a\": invalid syntax") var ui uint = 1 PanicMatches(t, func() { _ = validate.Var(ui, "len=a") }, "strconv.ParseUint: parsing \"a\": invalid syntax") f := 1.23 PanicMatches(t, func() { _ = validate.Var(f, "len=a") }, "strconv.ParseFloat: parsing \"a\": invalid syntax") } func TestLength(t *testing.T) { validate := New() i := true PanicMatches(t, func() { _ = validate.Var(i, "len") }, "Bad field type bool") } func TestIsGt(t *testing.T) { var errs error validate := New() myMap := map[string]string{} errs = validate.Var(myMap, "gt=0") NotEqual(t, errs, nil) f := 1.23 errs = validate.Var(f, "gt=5") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "gt") var ui uint = 5 errs = validate.Var(ui, "gt=10") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "gt") i := true PanicMatches(t, func() { _ = validate.Var(i, "gt") }, "Bad field type bool") tm := time.Now().UTC() tm = tm.Add(time.Hour * 24) errs = validate.Var(tm, "gt") Equal(t, errs, nil) t2 := time.Now().UTC().Add(-time.Hour) errs = validate.Var(t2, "gt") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "gt") type Test struct { Now *time.Time `validate:"gt"` } s := &Test{ Now: &tm, } errs = validate.Struct(s) Equal(t, errs, nil) s = &Test{ Now: &t2, } errs = validate.Struct(s) NotEqual(t, errs, nil) AssertError(t, errs, "Test.Now", "Test.Now", "Now", "Now", "gt") // Tests for time.Duration type. // -- Validations for a variable of time.Duration type. errs = validate.Var(time.Hour, "gt=59m") Equal(t, errs, nil) errs = validate.Var(time.Hour-time.Minute, "gt=59m") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "gt") errs = validate.Var(time.Hour-2*time.Minute, "gt=59m") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "gt") errs = validate.Var(time.Duration(0), "omitempty,gt=59m") Equal(t, errs, nil) // -- Validations for a struct with a time.Duration type field. type TimeDurationTest struct { Duration time.Duration `validate:"gt=59m"` } var timeDurationTest *TimeDurationTest timeDurationTest = &TimeDurationTest{time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) timeDurationTest = &TimeDurationTest{time.Hour - time.Minute} errs = validate.Struct(timeDurationTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeDurationTest.Duration", "TimeDurationTest.Duration", "Duration", "Duration", "gt") timeDurationTest = &TimeDurationTest{time.Hour - 2*time.Minute} errs = validate.Struct(timeDurationTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeDurationTest.Duration", "TimeDurationTest.Duration", "Duration", "Duration", "gt") type TimeDurationOmitemptyTest struct { Duration time.Duration `validate:"omitempty,gt=59m"` } timeDurationOmitemptyTest := &TimeDurationOmitemptyTest{time.Duration(0)} errs = validate.Struct(timeDurationOmitemptyTest) Equal(t, errs, nil) } func TestIsGte(t *testing.T) { var errs error validate := New() i := true PanicMatches(t, func() { _ = validate.Var(i, "gte") }, "Bad field type bool") t1 := time.Now().UTC() t1 = t1.Add(time.Hour * 24) errs = validate.Var(t1, "gte") Equal(t, errs, nil) t2 := time.Now().UTC().Add(-time.Hour) errs = validate.Var(t2, "gte") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "gte") type Test struct { Now *time.Time `validate:"gte"` } s := &Test{ Now: &t1, } errs = validate.Struct(s) Equal(t, errs, nil) s = &Test{ Now: &t2, } errs = validate.Struct(s) NotEqual(t, errs, nil) AssertError(t, errs, "Test.Now", "Test.Now", "Now", "Now", "gte") // Tests for time.Duration type. // -- Validations for a variable of time.Duration type. errs = validate.Var(time.Hour, "gte=59m") Equal(t, errs, nil) errs = validate.Var(time.Hour-time.Minute, "gte=59m") Equal(t, errs, nil) errs = validate.Var(time.Hour-2*time.Minute, "gte=59m") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "gte") errs = validate.Var(time.Duration(0), "omitempty,gte=59m") Equal(t, errs, nil) // -- Validations for a struct with a time.Duration type field. type TimeDurationTest struct { Duration time.Duration `validate:"gte=59m"` } var timeDurationTest *TimeDurationTest timeDurationTest = &TimeDurationTest{time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) timeDurationTest = &TimeDurationTest{time.Hour - time.Minute} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) timeDurationTest = &TimeDurationTest{time.Hour - 2*time.Minute} errs = validate.Struct(timeDurationTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeDurationTest.Duration", "TimeDurationTest.Duration", "Duration", "Duration", "gte") type TimeDurationOmitemptyTest struct { Duration time.Duration `validate:"omitempty,gte=59m"` } timeDurationOmitemptyTest := &TimeDurationOmitemptyTest{time.Duration(0)} errs = validate.Struct(timeDurationOmitemptyTest) Equal(t, errs, nil) } func TestMinValidation(t *testing.T) { var errs error validate := New() // Tests for time.Duration type. // -- Validations for a variable of time.Duration type. errs = validate.Var(time.Hour, "min=59m") Equal(t, errs, nil) errs = validate.Var(time.Hour-time.Minute, "min=59m") Equal(t, errs, nil) errs = validate.Var(time.Hour-2*time.Minute, "min=59m") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "min") errs = validate.Var(time.Duration(0), "omitempty,min=59m") Equal(t, errs, nil) // -- Validations for a struct with a time.Duration type field. type TimeDurationTest struct { Duration time.Duration `validate:"min=59m"` } var timeDurationTest *TimeDurationTest timeDurationTest = &TimeDurationTest{time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) timeDurationTest = &TimeDurationTest{time.Hour - time.Minute} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) timeDurationTest = &TimeDurationTest{time.Hour - 2*time.Minute} errs = validate.Struct(timeDurationTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeDurationTest.Duration", "TimeDurationTest.Duration", "Duration", "Duration", "min") type TimeDurationOmitemptyTest struct { Duration time.Duration `validate:"omitempty,min=59m"` } timeDurationOmitemptyTest := &TimeDurationOmitemptyTest{time.Duration(0)} errs = validate.Struct(timeDurationOmitemptyTest) Equal(t, errs, nil) } func TestMaxValidation(t *testing.T) { var errs error validate := New() // Tests for time.Duration type. // -- Validations for a variable of time.Duration type. errs = validate.Var(time.Hour, "max=1h1m") Equal(t, errs, nil) errs = validate.Var(time.Hour+time.Minute, "max=1h1m") Equal(t, errs, nil) errs = validate.Var(time.Hour+2*time.Minute, "max=1h1m") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "max") errs = validate.Var(time.Duration(0), "omitempty,max=-1s") Equal(t, errs, nil) // -- Validations for a struct with a time.Duration type field. type TimeDurationTest struct { Duration time.Duration `validate:"max=1h1m"` } var timeDurationTest *TimeDurationTest timeDurationTest = &TimeDurationTest{time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) timeDurationTest = &TimeDurationTest{time.Hour + time.Minute} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) timeDurationTest = &TimeDurationTest{time.Hour + 2*time.Minute} errs = validate.Struct(timeDurationTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeDurationTest.Duration", "TimeDurationTest.Duration", "Duration", "Duration", "max") type TimeDurationOmitemptyTest struct { Duration time.Duration `validate:"omitempty,max=-1s"` } timeDurationOmitemptyTest := &TimeDurationOmitemptyTest{time.Duration(0)} errs = validate.Struct(timeDurationOmitemptyTest) Equal(t, errs, nil) } func TestMinMaxValidation(t *testing.T) { var errs error validate := New() // Tests for time.Duration type. // -- Validations for a variable of time.Duration type. errs = validate.Var(time.Hour, "min=59m,max=1h1m") Equal(t, errs, nil) errs = validate.Var(time.Hour-time.Minute, "min=59m,max=1h1m") Equal(t, errs, nil) errs = validate.Var(time.Hour+time.Minute, "min=59m,max=1h1m") Equal(t, errs, nil) errs = validate.Var(time.Hour-2*time.Minute, "min=59m,max=1h1m") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "min") errs = validate.Var(time.Hour+2*time.Minute, "min=59m,max=1h1m") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "max") errs = validate.Var(time.Duration(0), "omitempty,min=59m,max=1h1m") Equal(t, errs, nil) // -- Validations for a struct with a time.Duration type field. type TimeDurationTest struct { Duration time.Duration `validate:"min=59m,max=1h1m"` } var timeDurationTest *TimeDurationTest timeDurationTest = &TimeDurationTest{time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) timeDurationTest = &TimeDurationTest{time.Hour - time.Minute} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) timeDurationTest = &TimeDurationTest{time.Hour + time.Minute} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) timeDurationTest = &TimeDurationTest{time.Hour - 2*time.Minute} errs = validate.Struct(timeDurationTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeDurationTest.Duration", "TimeDurationTest.Duration", "Duration", "Duration", "min") timeDurationTest = &TimeDurationTest{time.Hour + 2*time.Minute} errs = validate.Struct(timeDurationTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeDurationTest.Duration", "TimeDurationTest.Duration", "Duration", "Duration", "max") type TimeDurationOmitemptyTest struct { Duration time.Duration `validate:"omitempty,min=59m,max=1h1m"` } timeDurationOmitemptyTest := &TimeDurationOmitemptyTest{time.Duration(0)} errs = validate.Struct(timeDurationOmitemptyTest) Equal(t, errs, nil) } func TestLenValidation(t *testing.T) { var errs error validate := New() // Tests for time.Duration type. // -- Validations for a variable of time.Duration type. errs = validate.Var(time.Hour, "len=1h") Equal(t, errs, nil) errs = validate.Var(time.Hour-time.Minute, "len=1h") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "len") errs = validate.Var(time.Hour+time.Minute, "len=1h") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "len") errs = validate.Var(time.Duration(0), "omitempty,len=1h") Equal(t, errs, nil) // -- Validations for a struct with a time.Duration type field. type TimeDurationTest struct { Duration time.Duration `validate:"len=1h"` } var timeDurationTest *TimeDurationTest timeDurationTest = &TimeDurationTest{time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) timeDurationTest = &TimeDurationTest{time.Hour - time.Minute} errs = validate.Struct(timeDurationTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeDurationTest.Duration", "TimeDurationTest.Duration", "Duration", "Duration", "len") timeDurationTest = &TimeDurationTest{time.Hour + time.Minute} errs = validate.Struct(timeDurationTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeDurationTest.Duration", "TimeDurationTest.Duration", "Duration", "Duration", "len") type TimeDurationOmitemptyTest struct { Duration time.Duration `validate:"omitempty,len=1h"` } timeDurationOmitemptyTest := &TimeDurationOmitemptyTest{time.Duration(0)} errs = validate.Struct(timeDurationOmitemptyTest) Equal(t, errs, nil) } func TestIsLt(t *testing.T) { var errs error validate := New() myMap := map[string]string{} errs = validate.Var(myMap, "lt=0") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "lt") f := 1.23 errs = validate.Var(f, "lt=0") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "lt") var ui uint = 5 errs = validate.Var(ui, "lt=0") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "lt") i := true PanicMatches(t, func() { _ = validate.Var(i, "lt") }, "Bad field type bool") t1 := time.Now().UTC().Add(-time.Hour) errs = validate.Var(t1, "lt") Equal(t, errs, nil) t2 := time.Now().UTC() t2 = t2.Add(time.Hour * 24) errs = validate.Var(t2, "lt") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "lt") type Test struct { Now *time.Time `validate:"lt"` } s := &Test{ Now: &t1, } errs = validate.Struct(s) Equal(t, errs, nil) s = &Test{ Now: &t2, } errs = validate.Struct(s) NotEqual(t, errs, nil) AssertError(t, errs, "Test.Now", "Test.Now", "Now", "Now", "lt") // Tests for time.Duration type. // -- Validations for a variable of time.Duration type. errs = validate.Var(time.Hour, "lt=1h1m") Equal(t, errs, nil) errs = validate.Var(time.Hour+time.Minute, "lt=1h1m") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "lt") errs = validate.Var(time.Hour+2*time.Minute, "lt=1h1m") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "lt") errs = validate.Var(time.Duration(0), "omitempty,lt=0") Equal(t, errs, nil) // -- Validations for a struct with a time.Duration type field. type TimeDurationTest struct { Duration time.Duration `validate:"lt=1h1m"` } var timeDurationTest *TimeDurationTest timeDurationTest = &TimeDurationTest{time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) timeDurationTest = &TimeDurationTest{time.Hour + time.Minute} errs = validate.Struct(timeDurationTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeDurationTest.Duration", "TimeDurationTest.Duration", "Duration", "Duration", "lt") timeDurationTest = &TimeDurationTest{time.Hour + 2*time.Minute} errs = validate.Struct(timeDurationTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeDurationTest.Duration", "TimeDurationTest.Duration", "Duration", "Duration", "lt") type TimeDurationOmitemptyTest struct { Duration time.Duration `validate:"omitempty,lt=0"` } timeDurationOmitemptyTest := &TimeDurationOmitemptyTest{time.Duration(0)} errs = validate.Struct(timeDurationOmitemptyTest) Equal(t, errs, nil) } func TestIsLte(t *testing.T) { var errs error validate := New() i := true PanicMatches(t, func() { _ = validate.Var(i, "lte") }, "Bad field type bool") t1 := time.Now().UTC().Add(-time.Hour) errs = validate.Var(t1, "lte") Equal(t, errs, nil) t2 := time.Now().UTC() t2 = t2.Add(time.Hour * 24) errs = validate.Var(t2, "lte") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "lte") type Test struct { Now *time.Time `validate:"lte"` } s := &Test{ Now: &t1, } errs = validate.Struct(s) Equal(t, errs, nil) s = &Test{ Now: &t2, } errs = validate.Struct(s) NotEqual(t, errs, nil) // Tests for time.Duration type. // -- Validations for a variable of time.Duration type. errs = validate.Var(time.Hour, "lte=1h1m") Equal(t, errs, nil) errs = validate.Var(time.Hour+time.Minute, "lte=1h1m") Equal(t, errs, nil) errs = validate.Var(time.Hour+2*time.Minute, "lte=1h1m") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "lte") errs = validate.Var(time.Duration(0), "omitempty,lte=-1s") Equal(t, errs, nil) // -- Validations for a struct with a time.Duration type field. type TimeDurationTest struct { Duration time.Duration `validate:"lte=1h1m"` } var timeDurationTest *TimeDurationTest timeDurationTest = &TimeDurationTest{time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) timeDurationTest = &TimeDurationTest{time.Hour + time.Minute} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) timeDurationTest = &TimeDurationTest{time.Hour + 2*time.Minute} errs = validate.Struct(timeDurationTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeDurationTest.Duration", "TimeDurationTest.Duration", "Duration", "Duration", "lte") type TimeDurationOmitemptyTest struct { Duration time.Duration `validate:"omitempty,lte=-1s"` } timeDurationOmitemptyTest := &TimeDurationOmitemptyTest{time.Duration(0)} errs = validate.Struct(timeDurationOmitemptyTest) Equal(t, errs, nil) } func TestUrnRFC2141(t *testing.T) { var tests = []struct { param string expected bool }{ {"urn:a:b", true}, {"urn:a::", true}, {"urn:a:-", true}, {"URN:simple:simple", true}, {"urn:urna:simple", true}, {"urn:burnout:nss", true}, {"urn:burn:nss", true}, {"urn:urnurnurn:x", true}, {"urn:abcdefghilmnopqrstuvzabcdefghilm:x", true}, {"URN:123:x", true}, {"URN:abcd-:x", true}, {"URN:abcd-abcd:x", true}, {"urn:urnx:urn", true}, {"urn:ciao:a:b:c", true}, {"urn:aaa:x:y:", true}, {"urn:ciao:-", true}, {"urn:colon:::::nss", true}, {"urn:ciao:@!=%2C(xyz)+a,b.*@g=$_'", true}, {"URN:hexes:%25", true}, {"URN:x:abc%1Dz%2F%3az", true}, {"URN:foo:a123,456", true}, {"urn:foo:a123,456", true}, {"urn:FOO:a123,456", true}, {"urn:foo:A123,456", true}, {"urn:foo:a123%2C456", true}, {"URN:FOO:a123%2c456", true}, {"URN:FOO:ABC%FFabc123%2c456", true}, {"URN:FOO:ABC%FFabc123%2C456%9A", true}, {"urn:ietf:params:scim:schemas:core:2.0:User", true}, {"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:meta.lastModified", true}, {"URN:-xxx:x", false}, {"urn::colon:nss", false}, {"urn:abcdefghilmnopqrstuvzabcdefghilmn:specificstring", false}, {"URN:a!?:x", false}, {"URN:#,:x", false}, {"urn:urn:NSS", false}, {"urn:URN:NSS", false}, {"urn:white space:NSS", false}, {"urn:concat:no spaces", false}, {"urn:a:%", false}, {"urn:", false}, } tag := "urn_rfc2141" validate := New() for i, test := range tests { errs := validate.Var(test.param, tag) if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d URN failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d URN failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != tag { t.Fatalf("Index: %d URN failed Error: %s", i, errs) } } } } i := 1 PanicMatches(t, func() { _ = validate.Var(i, tag) }, "Bad field type int") } func TestUrl(t *testing.T) { var tests = []struct { param string expected bool }{ {"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", 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}, {"irc://#channel@network", true}, {"/abs/test/dir", false}, {"./rel/test/dir", false}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "url") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d URL failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d URL failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "url" { t.Fatalf("Index: %d URL failed Error: %s", i, errs) } } } } i := 1 PanicMatches(t, func() { _ = validate.Var(i, "url") }, "Bad field type int") } func TestUri(t *testing.T) { var tests = []struct { param string expected bool }{ {"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}, {"irc://#channel@network", true}, {"/abs/test/dir", true}, {"./rel/test/dir", false}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "uri") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d URI failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d URI failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "uri" { t.Fatalf("Index: %d URI failed Error: %s", i, errs) } } } } i := 1 PanicMatches(t, func() { _ = validate.Var(i, "uri") }, "Bad field type int") } func TestOrTag(t *testing.T) { validate := New() s := "rgba(0,31,255,0.5)" errs := validate.Var(s, "rgb|rgba") Equal(t, errs, nil) s = "rgba(0,31,255,0.5)" errs = validate.Var(s, "rgb|rgba|len=18") Equal(t, errs, nil) s = "this ain't right" errs = validate.Var(s, "rgb|rgba") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "rgb|rgba") s = "this ain't right" errs = validate.Var(s, "rgb|rgba|len=10") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "rgb|rgba|len=10") s = "this is right" errs = validate.Var(s, "rgb|rgba|len=13") Equal(t, errs, nil) s = "" errs = validate.Var(s, "omitempty,rgb|rgba") Equal(t, errs, nil) s = "green" errs = validate.Var(s, "eq=|eq=blue,rgb|rgba") //should fail on first validation block NotEqual(t, errs, nil) ve := errs.(ValidationErrors) Equal(t, len(ve), 1) Equal(t, ve[0].Tag(), "eq=|eq=blue") s = "this is right, but a blank or isn't" PanicMatches(t, func() { _ = validate.Var(s, "rgb||len=13") }, "Invalid validation tag on field ''") PanicMatches(t, func() { _ = validate.Var(s, "rgb|rgbaa|len=13") }, "Undefined validation function 'rgbaa' on field ''") v2 := New() v2.RegisterTagNameFunc(func(fld reflect.StructField) string { name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] if name == "-" { return "" } return name }) type Colors struct { Fav string `validate:"rgb|rgba" json:"fc"` } c := Colors{Fav: "this ain't right"} err := v2.Struct(c) NotEqual(t, err, nil) errs = err.(ValidationErrors) fe := getError(errs, "Colors.fc", "Colors.Fav") NotEqual(t, fe, nil) } func TestHsla(t *testing.T) { validate := New() s := "hsla(360,100%,100%,1)" errs := validate.Var(s, "hsla") Equal(t, errs, nil) s = "hsla(360,100%,100%,0.5)" errs = validate.Var(s, "hsla") Equal(t, errs, nil) s = "hsla(0,0%,0%, 0)" errs = validate.Var(s, "hsla") Equal(t, errs, nil) s = "hsl(361,100%,50%,1)" errs = validate.Var(s, "hsla") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "hsla") s = "hsl(361,100%,50%)" errs = validate.Var(s, "hsla") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "hsla") s = "hsla(361,100%,50%)" errs = validate.Var(s, "hsla") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "hsla") s = "hsla(360,101%,50%)" errs = validate.Var(s, "hsla") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "hsla") s = "hsla(360,100%,101%)" errs = validate.Var(s, "hsla") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "hsla") i := 1 errs = validate.Var(i, "hsla") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "hsla") } func TestHsl(t *testing.T) { validate := New() s := "hsl(360,100%,50%)" errs := validate.Var(s, "hsl") Equal(t, errs, nil) s = "hsl(0,0%,0%)" errs = validate.Var(s, "hsl") Equal(t, errs, nil) s = "hsl(361,100%,50%)" errs = validate.Var(s, "hsl") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "hsl") s = "hsl(361,101%,50%)" errs = validate.Var(s, "hsl") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "hsl") s = "hsl(361,100%,101%)" errs = validate.Var(s, "hsl") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "hsl") s = "hsl(-10,100%,100%)" errs = validate.Var(s, "hsl") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "hsl") i := 1 errs = validate.Var(i, "hsl") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "hsl") } func TestRgba(t *testing.T) { validate := New() s := "rgba(0,31,255,0.5)" errs := validate.Var(s, "rgba") Equal(t, errs, nil) s = "rgba(0,31,255,0.12)" errs = validate.Var(s, "rgba") Equal(t, errs, nil) s = "rgba(12%,55%,100%,0.12)" errs = validate.Var(s, "rgba") Equal(t, errs, nil) s = "rgba( 0, 31, 255, 0.5)" errs = validate.Var(s, "rgba") Equal(t, errs, nil) s = "rgba(12%,55,100%,0.12)" errs = validate.Var(s, "rgba") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "rgba") s = "rgb(0, 31, 255)" errs = validate.Var(s, "rgba") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "rgba") s = "rgb(1,349,275,0.5)" errs = validate.Var(s, "rgba") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "rgba") s = "rgb(01,31,255,0.5)" errs = validate.Var(s, "rgba") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "rgba") i := 1 errs = validate.Var(i, "rgba") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "rgba") } func TestRgb(t *testing.T) { validate := New() s := "rgb(0,31,255)" errs := validate.Var(s, "rgb") Equal(t, errs, nil) s = "rgb(0, 31, 255)" errs = validate.Var(s, "rgb") Equal(t, errs, nil) s = "rgb(10%, 50%, 100%)" errs = validate.Var(s, "rgb") Equal(t, errs, nil) s = "rgb(10%, 50%, 55)" errs = validate.Var(s, "rgb") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "rgb") s = "rgb(1,349,275)" errs = validate.Var(s, "rgb") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "rgb") s = "rgb(01,31,255)" errs = validate.Var(s, "rgb") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "rgb") s = "rgba(0,31,255)" errs = validate.Var(s, "rgb") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "rgb") i := 1 errs = validate.Var(i, "rgb") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "rgb") } func TestEmail(t *testing.T) { validate := New() s := "test@mail.com" errs := validate.Var(s, "email") Equal(t, errs, nil) s = "Dörte@Sörensen.example.com" errs = validate.Var(s, "email") Equal(t, errs, nil) s = "θσερ@εχαμπλε.ψομ" errs = validate.Var(s, "email") Equal(t, errs, nil) s = "юзер@екзампл.ком" errs = validate.Var(s, "email") Equal(t, errs, nil) s = "उपयोगकर्ता@उदाहरण.कॉम" errs = validate.Var(s, "email") Equal(t, errs, nil) s = "用户@例子.广告" errs = validate.Var(s, "email") Equal(t, errs, nil) s = "mail@domain_with_underscores.org" errs = validate.Var(s, "email") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "email") s = "" errs = validate.Var(s, "email") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "email") s = "test@email" errs = validate.Var(s, "email") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "email") s = "test@email." errs = validate.Var(s, "email") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "email") s = "@email.com" errs = validate.Var(s, "email") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "email") s = `"test test"@email.com` errs = validate.Var(s, "email") Equal(t, errs, nil) s = `"@email.com` errs = validate.Var(s, "email") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "email") i := true errs = validate.Var(i, "email") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "email") } func TestHexColor(t *testing.T) { validate := New() s := "#fff" errs := validate.Var(s, "hexcolor") Equal(t, errs, nil) s = "#c2c2c2" errs = validate.Var(s, "hexcolor") Equal(t, errs, nil) s = "fff" errs = validate.Var(s, "hexcolor") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "hexcolor") s = "fffFF" errs = validate.Var(s, "hexcolor") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "hexcolor") i := true errs = validate.Var(i, "hexcolor") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "hexcolor") } func TestHexadecimal(t *testing.T) { validate := New() s := "ff0044" errs := validate.Var(s, "hexadecimal") Equal(t, errs, nil) s = "0xff0044" errs = validate.Var(s, "hexadecimal") Equal(t, errs, nil) s = "0Xff0044" errs = validate.Var(s, "hexadecimal") Equal(t, errs, nil) s = "abcdefg" errs = validate.Var(s, "hexadecimal") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "hexadecimal") i := true errs = validate.Var(i, "hexadecimal") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "hexadecimal") } func TestNumber(t *testing.T) { validate := New() s := "1" errs := validate.Var(s, "number") Equal(t, errs, nil) s = "+1" errs = validate.Var(s, "number") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "number") s = "-1" errs = validate.Var(s, "number") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "number") s = "1.12" errs = validate.Var(s, "number") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "number") s = "+1.12" errs = validate.Var(s, "number") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "number") s = "-1.12" errs = validate.Var(s, "number") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "number") s = "1." errs = validate.Var(s, "number") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "number") s = "1.o" errs = validate.Var(s, "number") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "number") i := 1 errs = validate.Var(i, "number") Equal(t, errs, nil) } func TestNumeric(t *testing.T) { validate := New() s := "1" errs := validate.Var(s, "numeric") Equal(t, errs, nil) s = "+1" errs = validate.Var(s, "numeric") Equal(t, errs, nil) s = "-1" errs = validate.Var(s, "numeric") Equal(t, errs, nil) s = "1.12" errs = validate.Var(s, "numeric") Equal(t, errs, nil) s = "+1.12" errs = validate.Var(s, "numeric") Equal(t, errs, nil) s = "-1.12" errs = validate.Var(s, "numeric") Equal(t, errs, nil) s = "1." errs = validate.Var(s, "numeric") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "numeric") s = "1.o" errs = validate.Var(s, "numeric") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "numeric") i := 1 errs = validate.Var(i, "numeric") Equal(t, errs, nil) } func TestAlphaNumeric(t *testing.T) { validate := New() s := "abcd123" errs := validate.Var(s, "alphanum") Equal(t, errs, nil) s = "abc!23" errs = validate.Var(s, "alphanum") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "alphanum") errs = validate.Var(1, "alphanum") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "alphanum") } func TestAlpha(t *testing.T) { validate := New() s := "abcd" errs := validate.Var(s, "alpha") Equal(t, errs, nil) s = "abc®" errs = validate.Var(s, "alpha") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "alpha") s = "abc÷" errs = validate.Var(s, "alpha") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "alpha") s = "abc1" errs = validate.Var(s, "alpha") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "alpha") s = "this is a test string" errs = validate.Var(s, "alpha") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "alpha") errs = validate.Var(1, "alpha") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "alpha") } func TestStructStringValidation(t *testing.T) { validate := New() tSuccess := &TestString{ Required: "Required", Len: "length==10", Min: "min=1", Max: "1234567890", MinMax: "12345", Lt: "012345678", Lte: "0123456789", Gt: "01234567890", Gte: "0123456789", OmitEmpty: "", Sub: &SubTest{ Test: "1", }, SubIgnore: &SubTest{ Test: "", }, Anonymous: struct { A string `validate:"required"` }{ A: "1", }, Iface: &Impl{ F: "123", }, } errs := validate.Struct(tSuccess) Equal(t, errs, nil) tFail := &TestString{ Required: "", Len: "", Min: "", Max: "12345678901", MinMax: "", Lt: "0123456789", Lte: "01234567890", Gt: "1", Gte: "1", OmitEmpty: "12345678901", Sub: &SubTest{ Test: "", }, Anonymous: struct { A string `validate:"required"` }{ A: "", }, Iface: &Impl{ F: "12", }, } errs = validate.Struct(tFail) // Assert Top Level NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 13) // Assert Fields AssertError(t, errs, "TestString.Required", "TestString.Required", "Required", "Required", "required") AssertError(t, errs, "TestString.Len", "TestString.Len", "Len", "Len", "len") AssertError(t, errs, "TestString.Min", "TestString.Min", "Min", "Min", "min") AssertError(t, errs, "TestString.Max", "TestString.Max", "Max", "Max", "max") AssertError(t, errs, "TestString.MinMax", "TestString.MinMax", "MinMax", "MinMax", "min") AssertError(t, errs, "TestString.Lt", "TestString.Lt", "Lt", "Lt", "lt") AssertError(t, errs, "TestString.Lte", "TestString.Lte", "Lte", "Lte", "lte") AssertError(t, errs, "TestString.Gt", "TestString.Gt", "Gt", "Gt", "gt") AssertError(t, errs, "TestString.Gte", "TestString.Gte", "Gte", "Gte", "gte") AssertError(t, errs, "TestString.OmitEmpty", "TestString.OmitEmpty", "OmitEmpty", "OmitEmpty", "max") // Nested Struct Field Errs AssertError(t, errs, "TestString.Anonymous.A", "TestString.Anonymous.A", "A", "A", "required") AssertError(t, errs, "TestString.Sub.Test", "TestString.Sub.Test", "Test", "Test", "required") AssertError(t, errs, "TestString.Iface.F", "TestString.Iface.F", "F", "F", "len") } func TestStructInt32Validation(t *testing.T) { type TestInt32 struct { Required int `validate:"required"` Len int `validate:"len=10"` Min int `validate:"min=1"` Max int `validate:"max=10"` MinMax int `validate:"min=1,max=10"` Lt int `validate:"lt=10"` Lte int `validate:"lte=10"` Gt int `validate:"gt=10"` Gte int `validate:"gte=10"` OmitEmpty int `validate:"omitempty,min=1,max=10"` } tSuccess := &TestInt32{ Required: 1, Len: 10, Min: 1, Max: 10, MinMax: 5, Lt: 9, Lte: 10, Gt: 11, Gte: 10, OmitEmpty: 0, } validate := New() errs := validate.Struct(tSuccess) Equal(t, errs, nil) tFail := &TestInt32{ Required: 0, Len: 11, Min: -1, Max: 11, MinMax: -1, Lt: 10, Lte: 11, Gt: 10, Gte: 9, OmitEmpty: 11, } errs = validate.Struct(tFail) // Assert Top Level NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 10) // Assert Fields AssertError(t, errs, "TestInt32.Required", "TestInt32.Required", "Required", "Required", "required") AssertError(t, errs, "TestInt32.Len", "TestInt32.Len", "Len", "Len", "len") AssertError(t, errs, "TestInt32.Min", "TestInt32.Min", "Min", "Min", "min") AssertError(t, errs, "TestInt32.Max", "TestInt32.Max", "Max", "Max", "max") AssertError(t, errs, "TestInt32.MinMax", "TestInt32.MinMax", "MinMax", "MinMax", "min") AssertError(t, errs, "TestInt32.Lt", "TestInt32.Lt", "Lt", "Lt", "lt") AssertError(t, errs, "TestInt32.Lte", "TestInt32.Lte", "Lte", "Lte", "lte") AssertError(t, errs, "TestInt32.Gt", "TestInt32.Gt", "Gt", "Gt", "gt") AssertError(t, errs, "TestInt32.Gte", "TestInt32.Gte", "Gte", "Gte", "gte") AssertError(t, errs, "TestInt32.OmitEmpty", "TestInt32.OmitEmpty", "OmitEmpty", "OmitEmpty", "max") } func TestStructUint64Validation(t *testing.T) { validate := New() tSuccess := &TestUint64{ Required: 1, Len: 10, Min: 1, Max: 10, MinMax: 5, OmitEmpty: 0, } errs := validate.Struct(tSuccess) Equal(t, errs, nil) tFail := &TestUint64{ Required: 0, Len: 11, Min: 0, Max: 11, MinMax: 0, OmitEmpty: 11, } errs = validate.Struct(tFail) // Assert Top Level NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 6) // Assert Fields AssertError(t, errs, "TestUint64.Required", "TestUint64.Required", "Required", "Required", "required") AssertError(t, errs, "TestUint64.Len", "TestUint64.Len", "Len", "Len", "len") AssertError(t, errs, "TestUint64.Min", "TestUint64.Min", "Min", "Min", "min") AssertError(t, errs, "TestUint64.Max", "TestUint64.Max", "Max", "Max", "max") AssertError(t, errs, "TestUint64.MinMax", "TestUint64.MinMax", "MinMax", "MinMax", "min") AssertError(t, errs, "TestUint64.OmitEmpty", "TestUint64.OmitEmpty", "OmitEmpty", "OmitEmpty", "max") } func TestStructFloat64Validation(t *testing.T) { validate := New() tSuccess := &TestFloat64{ Required: 1, Len: 10, Min: 1, Max: 10, MinMax: 5, OmitEmpty: 0, } errs := validate.Struct(tSuccess) Equal(t, errs, nil) tFail := &TestFloat64{ Required: 0, Len: 11, Min: 0, Max: 11, MinMax: 0, OmitEmpty: 11, } errs = validate.Struct(tFail) // Assert Top Level NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 6) // Assert Fields AssertError(t, errs, "TestFloat64.Required", "TestFloat64.Required", "Required", "Required", "required") AssertError(t, errs, "TestFloat64.Len", "TestFloat64.Len", "Len", "Len", "len") AssertError(t, errs, "TestFloat64.Min", "TestFloat64.Min", "Min", "Min", "min") AssertError(t, errs, "TestFloat64.Max", "TestFloat64.Max", "Max", "Max", "max") AssertError(t, errs, "TestFloat64.MinMax", "TestFloat64.MinMax", "MinMax", "MinMax", "min") AssertError(t, errs, "TestFloat64.OmitEmpty", "TestFloat64.OmitEmpty", "OmitEmpty", "OmitEmpty", "max") } func TestStructSliceValidation(t *testing.T) { validate := New() tSuccess := &TestSlice{ Required: []int{1}, Len: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}, Min: []int{1, 2}, Max: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}, MinMax: []int{1, 2, 3, 4, 5}, OmitEmpty: nil, } errs := validate.Struct(tSuccess) Equal(t, errs, nil) tFail := &TestSlice{ Required: nil, Len: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1}, Min: []int{}, Max: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1}, MinMax: []int{}, OmitEmpty: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1}, } errs = validate.Struct(tFail) NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 6) // Assert Field Errors AssertError(t, errs, "TestSlice.Required", "TestSlice.Required", "Required", "Required", "required") AssertError(t, errs, "TestSlice.Len", "TestSlice.Len", "Len", "Len", "len") AssertError(t, errs, "TestSlice.Min", "TestSlice.Min", "Min", "Min", "min") AssertError(t, errs, "TestSlice.Max", "TestSlice.Max", "Max", "Max", "max") AssertError(t, errs, "TestSlice.MinMax", "TestSlice.MinMax", "MinMax", "MinMax", "min") AssertError(t, errs, "TestSlice.OmitEmpty", "TestSlice.OmitEmpty", "OmitEmpty", "OmitEmpty", "max") fe := getError(errs, "TestSlice.Len", "TestSlice.Len") NotEqual(t, fe, nil) Equal(t, fe.Field(), "Len") Equal(t, fe.StructField(), "Len") Equal(t, fe.Namespace(), "TestSlice.Len") Equal(t, fe.StructNamespace(), "TestSlice.Len") Equal(t, fe.Tag(), "len") Equal(t, fe.ActualTag(), "len") Equal(t, fe.Param(), "10") Equal(t, fe.Kind(), reflect.Slice) Equal(t, fe.Type(), reflect.TypeOf([]int{})) _, ok := fe.Value().([]int) Equal(t, ok, true) } func TestInvalidStruct(t *testing.T) { validate := New() s := &SubTest{ Test: "1", } err := validate.Struct(s.Test) NotEqual(t, err, nil) Equal(t, err.Error(), "validator: (nil string)") err = validate.Struct(nil) NotEqual(t, err, nil) Equal(t, err.Error(), "validator: (nil)") err = validate.StructPartial(nil, "SubTest.Test") NotEqual(t, err, nil) Equal(t, err.Error(), "validator: (nil)") err = validate.StructExcept(nil, "SubTest.Test") NotEqual(t, err, nil) Equal(t, err.Error(), "validator: (nil)") } func TestInvalidValidatorFunction(t *testing.T) { validate := New() s := &SubTest{ Test: "1", } PanicMatches(t, func() { _ = validate.Var(s.Test, "zzxxBadFunction") }, "Undefined validation function 'zzxxBadFunction' on field ''") } func TestCustomFieldName(t *testing.T) { validate := New() validate.RegisterTagNameFunc(func(fld reflect.StructField) string { name := strings.SplitN(fld.Tag.Get("schema"), ",", 2)[0] if name == "-" { return "" } return name }) type A struct { B string `schema:"b" validate:"required"` C string `schema:"c" validate:"required"` D []bool `schema:"d" validate:"required"` E string `schema:"-" validate:"required"` } a := &A{} err := validate.Struct(a) NotEqual(t, err, nil) errs := err.(ValidationErrors) Equal(t, len(errs), 4) Equal(t, getError(errs, "A.b", "A.B").Field(), "b") Equal(t, getError(errs, "A.c", "A.C").Field(), "c") Equal(t, getError(errs, "A.d", "A.D").Field(), "d") Equal(t, getError(errs, "A.E", "A.E").Field(), "E") v2 := New() err = v2.Struct(a) NotEqual(t, err, nil) errs = err.(ValidationErrors) Equal(t, len(errs), 4) Equal(t, getError(errs, "A.B", "A.B").Field(), "B") Equal(t, getError(errs, "A.C", "A.C").Field(), "C") Equal(t, getError(errs, "A.D", "A.D").Field(), "D") Equal(t, getError(errs, "A.E", "A.E").Field(), "E") } func TestMutipleRecursiveExtractStructCache(t *testing.T) { validate := New() type Recursive struct { Field *string `validate:"required,len=5,ne=string"` } var test Recursive current := reflect.ValueOf(test) name := "Recursive" proceed := make(chan struct{}) sc := validate.extractStructCache(current, name) ptr := fmt.Sprintf("%p", sc) for i := 0; i < 100; i++ { go func() { <-proceed sc := validate.extractStructCache(current, name) Equal(t, ptr, fmt.Sprintf("%p", sc)) }() } close(proceed) } // Thanks @robbrockbank, see https://github.com/go-playground/validator/issues/249 func TestPointerAndOmitEmpty(t *testing.T) { validate := New() type Test struct { MyInt *int `validate:"omitempty,gte=2,lte=255"` } val1 := 0 val2 := 256 t1 := Test{MyInt: &val1} // This should fail validation on gte because value is 0 t2 := Test{MyInt: &val2} // This should fail validate on lte because value is 256 t3 := Test{MyInt: nil} // This should succeed validation because pointer is nil errs := validate.Struct(t1) NotEqual(t, errs, nil) AssertError(t, errs, "Test.MyInt", "Test.MyInt", "MyInt", "MyInt", "gte") errs = validate.Struct(t2) NotEqual(t, errs, nil) AssertError(t, errs, "Test.MyInt", "Test.MyInt", "MyInt", "MyInt", "lte") errs = validate.Struct(t3) Equal(t, errs, nil) type TestIface struct { MyInt interface{} `validate:"omitempty,gte=2,lte=255"` } ti1 := TestIface{MyInt: &val1} // This should fail validation on gte because value is 0 ti2 := TestIface{MyInt: &val2} // This should fail validate on lte because value is 256 ti3 := TestIface{MyInt: nil} // This should succeed validation because pointer is nil errs = validate.Struct(ti1) NotEqual(t, errs, nil) AssertError(t, errs, "TestIface.MyInt", "TestIface.MyInt", "MyInt", "MyInt", "gte") errs = validate.Struct(ti2) NotEqual(t, errs, nil) AssertError(t, errs, "TestIface.MyInt", "TestIface.MyInt", "MyInt", "MyInt", "lte") errs = validate.Struct(ti3) Equal(t, errs, nil) } func TestRequired(t *testing.T) { validate := New() validate.RegisterTagNameFunc(func(fld reflect.StructField) string { name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] if name == "-" { return "" } return name }) type Test struct { Value interface{} `validate:"required"` } var test Test err := validate.Struct(test) NotEqual(t, err, nil) AssertError(t, err.(ValidationErrors), "Test.Value", "Test.Value", "Value", "Value", "required") } func TestBoolEqual(t *testing.T) { validate := New() type Test struct { Value bool `validate:"eq=true"` } var test Test err := validate.Struct(test) NotEqual(t, err, nil) AssertError(t, err.(ValidationErrors), "Test.Value", "Test.Value", "Value", "Value", "eq") test.Value = true err = validate.Struct(test) Equal(t, err, nil) } func TestTranslations(t *testing.T) { en := en.New() uni := ut.New(en, en, fr.New()) trans, _ := uni.GetTranslator("en") fr, _ := uni.GetTranslator("fr") validate := New() err := validate.RegisterTranslation("required", trans, func(ut ut.Translator) (err error) { // using this stype because multiple translation may have to be added for the full translation if err = ut.Add("required", "{0} is a required field", false); err != nil { return } return }, func(ut ut.Translator, fe FieldError) string { t, err := ut.T(fe.Tag(), fe.Field()) if err != nil { fmt.Printf("warning: error translating FieldError: %#v", fe.(*fieldError)) return fe.(*fieldError).Error() } return t }) Equal(t, err, nil) err = validate.RegisterTranslation("required", fr, func(ut ut.Translator) (err error) { // using this stype because multiple translation may have to be added for the full translation if err = ut.Add("required", "{0} est un champ obligatoire", false); err != nil { return } return }, func(ut ut.Translator, fe FieldError) string { t, transErr := ut.T(fe.Tag(), fe.Field()) if transErr != nil { fmt.Printf("warning: error translating FieldError: %#v", fe.(*fieldError)) return fe.(*fieldError).Error() } return t }) Equal(t, err, nil) type Test struct { Value interface{} `validate:"required"` } var test Test err = validate.Struct(test) NotEqual(t, err, nil) errs := err.(ValidationErrors) Equal(t, len(errs), 1) fe := errs[0] Equal(t, fe.Tag(), "required") Equal(t, fe.Namespace(), "Test.Value") Equal(t, fe.Translate(trans), fmt.Sprintf("%s is a required field", fe.Field())) Equal(t, fe.Translate(fr), fmt.Sprintf("%s est un champ obligatoire", fe.Field())) nl := nl.New() uni2 := ut.New(nl, nl) trans2, _ := uni2.GetTranslator("nl") Equal(t, fe.Translate(trans2), "Key: 'Test.Value' Error:Field validation for 'Value' failed on the 'required' tag") terrs := errs.Translate(trans) Equal(t, len(terrs), 1) v, ok := terrs["Test.Value"] Equal(t, ok, true) Equal(t, v, fmt.Sprintf("%s is a required field", fe.Field())) terrs = errs.Translate(fr) Equal(t, len(terrs), 1) v, ok = terrs["Test.Value"] Equal(t, ok, true) Equal(t, v, fmt.Sprintf("%s est un champ obligatoire", fe.Field())) type Test2 struct { Value string `validate:"gt=1"` } var t2 Test2 err = validate.Struct(t2) NotEqual(t, err, nil) errs = err.(ValidationErrors) Equal(t, len(errs), 1) fe = errs[0] Equal(t, fe.Tag(), "gt") Equal(t, fe.Namespace(), "Test2.Value") Equal(t, fe.Translate(trans), "Key: 'Test2.Value' Error:Field validation for 'Value' failed on the 'gt' tag") } func TestTranslationErrors(t *testing.T) { en := en.New() uni := ut.New(en, en, fr.New()) trans, _ := uni.GetTranslator("en") err := trans.Add("required", "{0} is a required field", false) // using translator outside of validator also Equal(t, err, nil) validate := New() err = validate.RegisterTranslation("required", trans, func(ut ut.Translator) (err error) { // using this stype because multiple translation may have to be added for the full translation if err = ut.Add("required", "{0} is a required field", false); err != nil { return } return }, func(ut ut.Translator, fe FieldError) string { t, err := ut.T(fe.Tag(), fe.Field()) if err != nil { fmt.Printf("warning: error translating FieldError: %#v", fe.(*fieldError)) return fe.(*fieldError).Error() } return t }) NotEqual(t, err, nil) Equal(t, err.Error(), "error: conflicting key 'required' rule 'Unknown' with text '{0} is a required field' for locale 'en', value being ignored") } func TestStructFiltered(t *testing.T) { p1 := func(ns []byte) bool { if bytes.HasSuffix(ns, []byte("NoTag")) || bytes.HasSuffix(ns, []byte("Required")) { return false } return true } p2 := func(ns []byte) bool { if bytes.HasSuffix(ns, []byte("SubSlice[0].Test")) || bytes.HasSuffix(ns, []byte("SubSlice[0]")) || bytes.HasSuffix(ns, []byte("SubSlice")) || bytes.HasSuffix(ns, []byte("Sub")) || bytes.HasSuffix(ns, []byte("SubIgnore")) || bytes.HasSuffix(ns, []byte("Anonymous")) || bytes.HasSuffix(ns, []byte("Anonymous.A")) { return false } return true } p3 := func(ns []byte) bool { return !bytes.HasSuffix(ns, []byte("SubTest.Test")) } // p4 := []string{ // "A", // } tPartial := &TestPartial{ NoTag: "NoTag", Required: "Required", SubSlice: []*SubTest{ { Test: "Required", }, { Test: "Required", }, }, Sub: &SubTest{ Test: "1", }, SubIgnore: &SubTest{ Test: "", }, Anonymous: struct { A string `validate:"required"` ASubSlice []*SubTest `validate:"required,dive"` SubAnonStruct []struct { Test string `validate:"required"` OtherTest string `validate:"required"` } `validate:"required,dive"` }{ A: "1", ASubSlice: []*SubTest{ { Test: "Required", }, { Test: "Required", }, }, SubAnonStruct: []struct { Test string `validate:"required"` OtherTest string `validate:"required"` }{ {"Required", "RequiredOther"}, {"Required", "RequiredOther"}, }, }, } validate := New() // the following should all return no errors as everything is valid in // the default state errs := validate.StructFilteredCtx(context.Background(), tPartial, p1) Equal(t, errs, nil) errs = validate.StructFiltered(tPartial, p2) Equal(t, errs, nil) // this isn't really a robust test, but is ment to illustrate the ANON CASE below errs = validate.StructFiltered(tPartial.SubSlice[0], p3) Equal(t, errs, nil) // mod tParial for required feild and re-test making sure invalid fields are NOT required: tPartial.Required = "" // inversion and retesting Partial to generate failures: errs = validate.StructFiltered(tPartial, p1) NotEqual(t, errs, nil) AssertError(t, errs, "TestPartial.Required", "TestPartial.Required", "Required", "Required", "required") // reset Required field, and set nested struct tPartial.Required = "Required" tPartial.Anonymous.A = "" // will pass as unset feilds is not going to be tested errs = validate.StructFiltered(tPartial, p1) Equal(t, errs, nil) // will fail as unset feild is tested errs = validate.StructFiltered(tPartial, p2) NotEqual(t, errs, nil) AssertError(t, errs, "TestPartial.Anonymous.A", "TestPartial.Anonymous.A", "A", "A", "required") // reset nested struct and unset struct in slice tPartial.Anonymous.A = "Required" tPartial.SubSlice[0].Test = "" // these will pass as unset item is NOT tested errs = validate.StructFiltered(tPartial, p1) Equal(t, errs, nil) errs = validate.StructFiltered(tPartial, p2) NotEqual(t, errs, nil) AssertError(t, errs, "TestPartial.SubSlice[0].Test", "TestPartial.SubSlice[0].Test", "Test", "Test", "required") Equal(t, len(errs.(ValidationErrors)), 1) // Unset second slice member concurrently to test dive behavior: tPartial.SubSlice[1].Test = "" errs = validate.StructFiltered(tPartial, p1) Equal(t, errs, nil) errs = validate.StructFiltered(tPartial, p2) NotEqual(t, errs, nil) Equal(t, len(errs.(ValidationErrors)), 1) AssertError(t, errs, "TestPartial.SubSlice[0].Test", "TestPartial.SubSlice[0].Test", "Test", "Test", "required") // reset struct in slice, and unset struct in slice in unset posistion tPartial.SubSlice[0].Test = "Required" // these will pass as the unset item is NOT tested errs = validate.StructFiltered(tPartial, p1) Equal(t, errs, nil) errs = validate.StructFiltered(tPartial, p2) Equal(t, errs, nil) tPartial.SubSlice[1].Test = "Required" tPartial.Anonymous.SubAnonStruct[0].Test = "" // these will pass as the unset item is NOT tested errs = validate.StructFiltered(tPartial, p1) Equal(t, errs, nil) errs = validate.StructFiltered(tPartial, p2) Equal(t, errs, nil) dt := time.Now() err := validate.StructFiltered(&dt, func(ns []byte) bool { return true }) NotEqual(t, err, nil) Equal(t, err.Error(), "validator: (nil *time.Time)") } func TestRequiredPtr(t *testing.T) { type Test struct { Bool *bool `validate:"required"` } validate := New() f := false test := Test{ Bool: &f, } err := validate.Struct(test) Equal(t, err, nil) tr := true test.Bool = &tr err = validate.Struct(test) Equal(t, err, nil) test.Bool = nil err = validate.Struct(test) NotEqual(t, err, nil) errs, ok := err.(ValidationErrors) Equal(t, ok, true) Equal(t, len(errs), 1) AssertError(t, errs, "Test.Bool", "Test.Bool", "Bool", "Bool", "required") type Test2 struct { Bool bool `validate:"required"` } var test2 Test2 err = validate.Struct(test2) NotEqual(t, err, nil) errs, ok = err.(ValidationErrors) Equal(t, ok, true) Equal(t, len(errs), 1) AssertError(t, errs, "Test2.Bool", "Test2.Bool", "Bool", "Bool", "required") test2.Bool = true err = validate.Struct(test2) Equal(t, err, nil) type Test3 struct { Arr []string `validate:"required"` } var test3 Test3 err = validate.Struct(test3) NotEqual(t, err, nil) errs, ok = err.(ValidationErrors) Equal(t, ok, true) Equal(t, len(errs), 1) AssertError(t, errs, "Test3.Arr", "Test3.Arr", "Arr", "Arr", "required") test3.Arr = make([]string, 0) err = validate.Struct(test3) Equal(t, err, nil) type Test4 struct { Arr *[]string `validate:"required"` // I know I know pointer to array, just making sure validation works as expected... } var test4 Test4 err = validate.Struct(test4) NotEqual(t, err, nil) errs, ok = err.(ValidationErrors) Equal(t, ok, true) Equal(t, len(errs), 1) AssertError(t, errs, "Test4.Arr", "Test4.Arr", "Arr", "Arr", "required") arr := make([]string, 0) test4.Arr = &arr err = validate.Struct(test4) Equal(t, err, nil) } func TestAlphaUnicodeValidation(t *testing.T) { tests := []struct { param string expected bool }{ {"", false}, {"abc", true}, {"this is a test string", false}, {"这是一个测试字符串", true}, {"123", false}, {"<>@;.-=", false}, {"ひらがな・カタカナ、.漢字", false}, {"あいうえおfoobar", true}, {"test@example.com", false}, {"1234abcDE", false}, {"カタカナ", true}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "alphaunicode") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d Alpha Unicode failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d Alpha Unicode failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "alphaunicode" { t.Fatalf("Index: %d Alpha Unicode failed Error: %s", i, errs) } } } } } func TestAlphanumericUnicodeValidation(t *testing.T) { tests := []struct { param string expected bool }{ {"", false}, {"abc", true}, {"this is a test string", false}, {"这是一个测试字符串", true}, {"\u0031\u0032\u0033", true}, // unicode 5 {"123", true}, {"<>@;.-=", false}, {"ひらがな・カタカナ、.漢字", false}, {"あいうえおfoobar", true}, {"test@example.com", false}, {"1234abcDE", true}, {"カタカナ", true}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "alphanumunicode") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d Alphanum Unicode failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d Alphanum Unicode failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "alphanumunicode" { t.Fatalf("Index: %d Alphanum Unicode failed Error: %s", i, errs) } } } } } func TestArrayStructNamespace(t *testing.T) { validate := New() validate.RegisterTagNameFunc(func(fld reflect.StructField) string { name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] if name == "-" { return "" } return name }) type child struct { Name string `json:"name" validate:"required"` } var input struct { Children []child `json:"children" validate:"required,gt=0,dive"` } input.Children = []child{{"ok"}, {""}} errs := validate.Struct(input) NotEqual(t, errs, nil) ve := errs.(ValidationErrors) Equal(t, len(ve), 1) AssertError(t, errs, "children[1].name", "Children[1].Name", "name", "Name", "required") } func TestMapStructNamespace(t *testing.T) { validate := New() validate.RegisterTagNameFunc(func(fld reflect.StructField) string { name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] if name == "-" { return "" } return name }) type child struct { Name string `json:"name" validate:"required"` } var input struct { Children map[int]child `json:"children" validate:"required,gt=0,dive"` } input.Children = map[int]child{ 0: {Name: "ok"}, 1: {Name: ""}, } errs := validate.Struct(input) NotEqual(t, errs, nil) ve := errs.(ValidationErrors) Equal(t, len(ve), 1) AssertError(t, errs, "children[1].name", "Children[1].Name", "name", "Name", "required") } func TestFieldLevelName(t *testing.T) { type Test struct { String string `validate:"custom1" json:"json1"` Array []string `validate:"dive,custom2" json:"json2"` Map map[string]string `validate:"dive,custom3" json:"json3"` Array2 []string `validate:"custom4" json:"json4"` Map2 map[string]string `validate:"custom5" json:"json5"` } var res1, res2, res3, res4, res5, alt1, alt2, alt3, alt4, alt5 string validate := New() validate.RegisterTagNameFunc(func(fld reflect.StructField) string { name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] if name == "-" { return "" } return name }) err := validate.RegisterValidation("custom1", func(fl FieldLevel) bool { res1 = fl.FieldName() alt1 = fl.StructFieldName() return true }) Equal(t, err, nil) err = validate.RegisterValidation("custom2", func(fl FieldLevel) bool { res2 = fl.FieldName() alt2 = fl.StructFieldName() return true }) Equal(t, err, nil) err = validate.RegisterValidation("custom3", func(fl FieldLevel) bool { res3 = fl.FieldName() alt3 = fl.StructFieldName() return true }) Equal(t, err, nil) err = validate.RegisterValidation("custom4", func(fl FieldLevel) bool { res4 = fl.FieldName() alt4 = fl.StructFieldName() return true }) Equal(t, err, nil) err = validate.RegisterValidation("custom5", func(fl FieldLevel) bool { res5 = fl.FieldName() alt5 = fl.StructFieldName() return true }) Equal(t, err, nil) test := Test{ String: "test", Array: []string{"1"}, Map: map[string]string{"test": "test"}, } errs := validate.Struct(test) Equal(t, errs, nil) Equal(t, res1, "json1") Equal(t, alt1, "String") Equal(t, res2, "json2[0]") Equal(t, alt2, "Array[0]") Equal(t, res3, "json3[test]") Equal(t, alt3, "Map[test]") Equal(t, res4, "json4") Equal(t, alt4, "Array2") Equal(t, res5, "json5") Equal(t, alt5, "Map2") } func TestValidateStructRegisterCtx(t *testing.T) { var ctxVal string fnCtx := func(ctx context.Context, fl FieldLevel) bool { ctxVal = ctx.Value(&ctxVal).(string) return true } var ctxSlVal string slFn := func(ctx context.Context, sl StructLevel) { ctxSlVal = ctx.Value(&ctxSlVal).(string) } type Test struct { Field string `validate:"val"` } var tst Test validate := New() err := validate.RegisterValidationCtx("val", fnCtx) Equal(t, err, nil) validate.RegisterStructValidationCtx(slFn, Test{}) ctx := context.WithValue(context.Background(), &ctxVal, "testval") ctx = context.WithValue(ctx, &ctxSlVal, "slVal") errs := validate.StructCtx(ctx, tst) Equal(t, errs, nil) Equal(t, ctxVal, "testval") Equal(t, ctxSlVal, "slVal") } func TestHostnameRFC952Validation(t *testing.T) { tests := []struct { param string expected bool }{ {"test.example.com", true}, {"example.com", true}, {"example24.com", true}, {"test.example24.com", true}, {"test24.example24.com", true}, {"example", true}, {"EXAMPLE", true}, {"1.foo.com", false}, {"test.example.com.", false}, {"example.com.", false}, {"example24.com.", false}, {"test.example24.com.", false}, {"test24.example24.com.", false}, {"example.", false}, {"192.168.0.1", false}, {"email@example.com", false}, {"2001:cdba:0000:0000:0000:0000:3257:9652", false}, {"2001:cdba:0:0:0:0:3257:9652", false}, {"2001:cdba::3257:9652", false}, {"example..........com", false}, {"1234", false}, {"abc1234", true}, {"example. com", false}, {"ex ample.com", false}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "hostname") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d hostname failed Error: %v", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d hostname failed Error: %v", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "hostname" { t.Fatalf("Index: %d hostname failed Error: %v", i, errs) } } } } } func TestHostnameRFC1123Validation(t *testing.T) { tests := []struct { param string expected bool }{ {"test.example.com", true}, {"example.com", true}, {"example24.com", true}, {"test.example24.com", true}, {"test24.example24.com", true}, {"example", true}, {"1.foo.com", true}, {"test.example.com.", false}, {"example.com.", false}, {"example24.com.", false}, {"test.example24.com.", false}, {"test24.example24.com.", false}, {"example.", false}, {"192.168.0.1", true}, {"email@example.com", false}, {"2001:cdba:0000:0000:0000:0000:3257:9652", false}, {"2001:cdba:0:0:0:0:3257:9652", false}, {"2001:cdba::3257:9652", false}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "hostname_rfc1123") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Hostname: %v failed Error: %v", test, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Hostname: %v failed Error: %v", test, errs) } else { val := getError(errs, "", "") if val.Tag() != "hostname_rfc1123" { t.Fatalf("Hostname: %v failed Error: %v", i, errs) } } } } } func TestHostnameRFC1123AliasValidation(t *testing.T) { tests := []struct { param string expected bool }{ {"test.example.com", true}, {"example.com", true}, {"example24.com", true}, {"test.example24.com", true}, {"test24.example24.com", true}, {"example", true}, {"1.foo.com", true}, {"test.example.com.", false}, {"example.com.", false}, {"example24.com.", false}, {"test.example24.com.", false}, {"test24.example24.com.", false}, {"example.", false}, {"192.168.0.1", true}, {"email@example.com", false}, {"2001:cdba:0000:0000:0000:0000:3257:9652", false}, {"2001:cdba:0:0:0:0:3257:9652", false}, {"2001:cdba::3257:9652", false}, } validate := New() validate.RegisterAlias("hostname", "hostname_rfc1123") for i, test := range tests { errs := validate.Var(test.param, "hostname") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d hostname failed Error: %v", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d hostname failed Error: %v", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "hostname" { t.Fatalf("Index: %d hostname failed Error: %v", i, errs) } } } } } func TestFQDNValidation(t *testing.T) { tests := []struct { param string expected bool }{ {"test.example.com", true}, {"example.com", true}, {"example24.com", true}, {"test.example24.com", true}, {"test24.example24.com", true}, {"test.example.com.", true}, {"example.com.", true}, {"example24.com.", true}, {"test.example24.com.", true}, {"test24.example24.com.", true}, {"24.example24.com", true}, {"test.24.example.com", true}, {"test24.example24.com..", false}, {"example", false}, {"192.168.0.1", false}, {"email@example.com", false}, {"2001:cdba:0000:0000:0000:0000:3257:9652", false}, {"2001:cdba:0:0:0:0:3257:9652", false}, {"2001:cdba::3257:9652", false}, {"", false}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "fqdn") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d fqdn failed Error: %v", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d fqdn failed Error: %v", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "fqdn" { t.Fatalf("Index: %d fqdn failed Error: %v", i, errs) } } } } } func TestIsDefault(t *testing.T) { validate := New() type Inner struct { String string `validate:"isdefault"` } type Test struct { String string `validate:"isdefault"` Inner *Inner `validate:"isdefault"` } var tt Test errs := validate.Struct(tt) Equal(t, errs, nil) tt.Inner = &Inner{String: ""} errs = validate.Struct(tt) NotEqual(t, errs, nil) fe := errs.(ValidationErrors)[0] Equal(t, fe.Field(), "Inner") Equal(t, fe.Namespace(), "Test.Inner") Equal(t, fe.Tag(), "isdefault") validate.RegisterTagNameFunc(func(fld reflect.StructField) string { name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] if name == "-" { return "" } return name }) type Inner2 struct { String string `validate:"isdefault"` } type Test2 struct { Inner Inner2 `validate:"isdefault" json:"inner"` } var t2 Test2 errs = validate.Struct(t2) Equal(t, errs, nil) t2.Inner.String = "Changed" errs = validate.Struct(t2) NotEqual(t, errs, nil) fe = errs.(ValidationErrors)[0] Equal(t, fe.Field(), "inner") Equal(t, fe.Namespace(), "Test2.inner") Equal(t, fe.Tag(), "isdefault") } func TestUniqueValidation(t *testing.T) { tests := []struct { param interface{} expected bool }{ // Arrays {[2]string{"a", "b"}, true}, {[2]int{1, 2}, true}, {[2]float64{1, 2}, true}, {[2]interface{}{"a", "b"}, true}, {[2]interface{}{"a", 1}, true}, {[2]float64{1, 1}, false}, {[2]int{1, 1}, false}, {[2]string{"a", "a"}, false}, {[2]interface{}{"a", "a"}, false}, {[4]interface{}{"a", 1, "b", 1}, false}, {[2]*string{stringPtr("a"), stringPtr("b")}, true}, {[2]*int{intPtr(1), intPtr(2)}, true}, {[2]*float64{float64Ptr(1), float64Ptr(2)}, true}, {[2]*string{stringPtr("a"), stringPtr("a")}, false}, {[2]*float64{float64Ptr(1), float64Ptr(1)}, false}, {[2]*int{intPtr(1), intPtr(1)}, false}, // Slices {[]string{"a", "b"}, true}, {[]int{1, 2}, true}, {[]float64{1, 2}, true}, {[]interface{}{"a", "b"}, true}, {[]interface{}{"a", 1}, true}, {[]float64{1, 1}, false}, {[]int{1, 1}, false}, {[]string{"a", "a"}, false}, {[]interface{}{"a", "a"}, false}, {[]interface{}{"a", 1, "b", 1}, false}, {[]*string{stringPtr("a"), stringPtr("b")}, true}, {[]*int{intPtr(1), intPtr(2)}, true}, {[]*float64{float64Ptr(1), float64Ptr(2)}, true}, {[]*string{stringPtr("a"), stringPtr("a")}, false}, {[]*float64{float64Ptr(1), float64Ptr(1)}, false}, {[]*int{intPtr(1), intPtr(1)}, false}, // Maps {map[string]string{"one": "a", "two": "b"}, true}, {map[string]int{"one": 1, "two": 2}, true}, {map[string]float64{"one": 1, "two": 2}, true}, {map[string]interface{}{"one": "a", "two": "b"}, true}, {map[string]interface{}{"one": "a", "two": 1}, true}, {map[string]float64{"one": 1, "two": 1}, false}, {map[string]int{"one": 1, "two": 1}, false}, {map[string]string{"one": "a", "two": "a"}, false}, {map[string]interface{}{"one": "a", "two": "a"}, false}, {map[string]interface{}{"one": "a", "two": 1, "three": "b", "four": 1}, false}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "unique") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d unique failed Error: %v", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d unique failed Error: %v", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "unique" { t.Fatalf("Index: %d unique failed Error: %v", i, errs) } } } } PanicMatches(t, func() { _ = validate.Var(1.0, "unique") }, "Bad field type float64") } func TestUniqueValidationStructSlice(t *testing.T) { testStructs := []struct { A string B string }{ {A: "one", B: "two"}, {A: "one", B: "three"}, } tests := []struct { target interface{} param string expected bool }{ {testStructs, "unique", true}, {testStructs, "unique=A", false}, {testStructs, "unique=B", true}, } validate := New() for i, test := range tests { errs := validate.Var(test.target, test.param) if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d unique failed Error: %v", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d unique failed Error: %v", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "unique" { t.Fatalf("Index: %d unique failed Error: %v", i, errs) } } } } PanicMatches(t, func() { _ = validate.Var(testStructs, "unique=C") }, "Bad field name C") } func TestUniqueValidationStructPtrSlice(t *testing.T) { testStructs := []*struct { A *string B *string }{ {A: stringPtr("one"), B: stringPtr("two")}, {A: stringPtr("one"), B: stringPtr("three")}, } tests := []struct { target interface{} param string expected bool }{ {testStructs, "unique", true}, {testStructs, "unique=A", false}, {testStructs, "unique=B", true}, } validate := New() for i, test := range tests { errs := validate.Var(test.target, test.param) if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d unique failed Error: %v", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d unique failed Error: %v", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "unique" { t.Fatalf("Index: %d unique failed Error: %v", i, errs) } } } } PanicMatches(t, func() { _ = validate.Var(testStructs, "unique=C") }, "Bad field name C") } func TestHTMLValidation(t *testing.T) { tests := []struct { param string expected bool }{ {"", true}, {"", true}, {"", false}, {"<123nonsense>", false}, {"test", false}, {"&example", false}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "html") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d html failed Error: %v", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d html failed Error: %v", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "html" { t.Fatalf("Index: %d html failed Error: %v", i, errs) } } } } } func TestHTMLEncodedValidation(t *testing.T) { tests := []struct { param string expected bool }{ {"<", true}, {"¯", true}, {"�", true}, {"ð", true}, {"<", true}, {"¯", true}, {"�", true}, {"ð", true}, {"&#ab", true}, {"<", true}, {">", true}, {""", true}, {"&", true}, {"#x0a", false}, {"&x00", false}, {"z", false}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "html_encoded") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d html_encoded failed Error: %v", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d html_enocded failed Error: %v", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "html_encoded" { t.Fatalf("Index: %d html_encoded failed Error: %v", i, errs) } } } } } func TestURLEncodedValidation(t *testing.T) { tests := []struct { param string expected bool }{ {"%20", true}, {"%af", true}, {"%ff", true}, {"<%az", false}, {"%test%", false}, {"a%b", false}, {"1%2", false}, {"%%a%%", false}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "url_encoded") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d url_encoded failed Error: %v", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d url_enocded failed Error: %v", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "url_encoded" { t.Fatalf("Index: %d url_encoded failed Error: %v", i, errs) } } } } } func TestKeys(t *testing.T) { type Test struct { Test1 map[string]string `validate:"gt=0,dive,keys,eq=testkey,endkeys,eq=testval" json:"test1"` Test2 map[int]int `validate:"gt=0,dive,keys,eq=3,endkeys,eq=4" json:"test2"` Test3 map[int]int `validate:"gt=0,dive,keys,eq=3,endkeys" json:"test3"` } var tst Test validate := New() err := validate.Struct(tst) NotEqual(t, err, nil) Equal(t, len(err.(ValidationErrors)), 3) AssertError(t, err.(ValidationErrors), "Test.Test1", "Test.Test1", "Test1", "Test1", "gt") AssertError(t, err.(ValidationErrors), "Test.Test2", "Test.Test2", "Test2", "Test2", "gt") AssertError(t, err.(ValidationErrors), "Test.Test3", "Test.Test3", "Test3", "Test3", "gt") tst.Test1 = map[string]string{ "testkey": "testval", } tst.Test2 = map[int]int{ 3: 4, } tst.Test3 = map[int]int{ 3: 4, } err = validate.Struct(tst) Equal(t, err, nil) tst.Test1["badtestkey"] = "badtestvalue" tst.Test2[10] = 11 err = validate.Struct(tst) NotEqual(t, err, nil) errs := err.(ValidationErrors) Equal(t, len(errs), 4) AssertDeepError(t, errs, "Test.Test1[badtestkey]", "Test.Test1[badtestkey]", "Test1[badtestkey]", "Test1[badtestkey]", "eq", "eq") AssertDeepError(t, errs, "Test.Test1[badtestkey]", "Test.Test1[badtestkey]", "Test1[badtestkey]", "Test1[badtestkey]", "eq", "eq") AssertDeepError(t, errs, "Test.Test2[10]", "Test.Test2[10]", "Test2[10]", "Test2[10]", "eq", "eq") AssertDeepError(t, errs, "Test.Test2[10]", "Test.Test2[10]", "Test2[10]", "Test2[10]", "eq", "eq") type Test2 struct { NestedKeys map[[1]string]string `validate:"gt=0,dive,keys,dive,eq=innertestkey,endkeys,eq=outertestval"` } var tst2 Test2 err = validate.Struct(tst2) NotEqual(t, err, nil) Equal(t, len(err.(ValidationErrors)), 1) AssertError(t, err.(ValidationErrors), "Test2.NestedKeys", "Test2.NestedKeys", "NestedKeys", "NestedKeys", "gt") tst2.NestedKeys = map[[1]string]string{ [1]string{"innertestkey"}: "outertestval", } err = validate.Struct(tst2) Equal(t, err, nil) tst2.NestedKeys[[1]string{"badtestkey"}] = "badtestvalue" err = validate.Struct(tst2) NotEqual(t, err, nil) errs = err.(ValidationErrors) Equal(t, len(errs), 2) AssertDeepError(t, errs, "Test2.NestedKeys[[badtestkey]][0]", "Test2.NestedKeys[[badtestkey]][0]", "NestedKeys[[badtestkey]][0]", "NestedKeys[[badtestkey]][0]", "eq", "eq") AssertDeepError(t, errs, "Test2.NestedKeys[[badtestkey]]", "Test2.NestedKeys[[badtestkey]]", "NestedKeys[[badtestkey]]", "NestedKeys[[badtestkey]]", "eq", "eq") // test bad tag definitions PanicMatches(t, func() { _ = validate.Var(map[string]string{"key": "val"}, "endkeys,dive,eq=val") }, "'endkeys' tag encountered without a corresponding 'keys' tag") PanicMatches(t, func() { _ = validate.Var(1, "keys,eq=1,endkeys") }, "'keys' tag must be immediately preceded by the 'dive' tag") // test custom tag name validate = New() validate.RegisterTagNameFunc(func(fld reflect.StructField) string { name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] if name == "-" { return "" } return name }) err = validate.Struct(tst) NotEqual(t, err, nil) errs = err.(ValidationErrors) Equal(t, len(errs), 4) AssertDeepError(t, errs, "Test.test1[badtestkey]", "Test.Test1[badtestkey]", "test1[badtestkey]", "Test1[badtestkey]", "eq", "eq") AssertDeepError(t, errs, "Test.test1[badtestkey]", "Test.Test1[badtestkey]", "test1[badtestkey]", "Test1[badtestkey]", "eq", "eq") AssertDeepError(t, errs, "Test.test2[10]", "Test.Test2[10]", "test2[10]", "Test2[10]", "eq", "eq") AssertDeepError(t, errs, "Test.test2[10]", "Test.Test2[10]", "test2[10]", "Test2[10]", "eq", "eq") } // Thanks @adrian-sgn specific test for your specific scenario func TestKeysCustomValidation(t *testing.T) { type LangCode string type Label map[LangCode]string type TestMapStructPtr struct { Label Label `validate:"dive,keys,lang_code,endkeys,required"` } validate := New() err := validate.RegisterValidation("lang_code", func(fl FieldLevel) bool { validLangCodes := map[LangCode]struct{}{ "en": {}, "es": {}, "pt": {}, } _, ok := validLangCodes[fl.Field().Interface().(LangCode)] return ok }) Equal(t, err, nil) label := Label{ "en": "Good morning!", "pt": "", "es": "¡Buenos días!", "xx": "Bad key", "xxx": "", } err = validate.Struct(TestMapStructPtr{label}) NotEqual(t, err, nil) errs := err.(ValidationErrors) Equal(t, len(errs), 4) AssertDeepError(t, errs, "TestMapStructPtr.Label[xx]", "TestMapStructPtr.Label[xx]", "Label[xx]", "Label[xx]", "lang_code", "lang_code") AssertDeepError(t, errs, "TestMapStructPtr.Label[pt]", "TestMapStructPtr.Label[pt]", "Label[pt]", "Label[pt]", "required", "required") AssertDeepError(t, errs, "TestMapStructPtr.Label[xxx]", "TestMapStructPtr.Label[xxx]", "Label[xxx]", "Label[xxx]", "lang_code", "lang_code") AssertDeepError(t, errs, "TestMapStructPtr.Label[xxx]", "TestMapStructPtr.Label[xxx]", "Label[xxx]", "Label[xxx]", "required", "required") // find specific error var e FieldError for _, e = range errs { if e.Namespace() == "TestMapStructPtr.Label[xxx]" { break } } Equal(t, e.Param(), "") Equal(t, e.Value().(LangCode), LangCode("xxx")) for _, e = range errs { if e.Namespace() == "TestMapStructPtr.Label[xxx]" && e.Tag() == "required" { break } } Equal(t, e.Param(), "") Equal(t, e.Value().(string), "") } func TestKeyOrs(t *testing.T) { type Test struct { Test1 map[string]string `validate:"gt=0,dive,keys,eq=testkey|eq=testkeyok,endkeys,eq=testval" json:"test1"` } var tst Test validate := New() err := validate.Struct(tst) NotEqual(t, err, nil) Equal(t, len(err.(ValidationErrors)), 1) AssertError(t, err.(ValidationErrors), "Test.Test1", "Test.Test1", "Test1", "Test1", "gt") tst.Test1 = map[string]string{ "testkey": "testval", } err = validate.Struct(tst) Equal(t, err, nil) tst.Test1["badtestkey"] = "badtestval" err = validate.Struct(tst) NotEqual(t, err, nil) errs := err.(ValidationErrors) Equal(t, len(errs), 2) AssertDeepError(t, errs, "Test.Test1[badtestkey]", "Test.Test1[badtestkey]", "Test1[badtestkey]", "Test1[badtestkey]", "eq=testkey|eq=testkeyok", "eq=testkey|eq=testkeyok") AssertDeepError(t, errs, "Test.Test1[badtestkey]", "Test.Test1[badtestkey]", "Test1[badtestkey]", "Test1[badtestkey]", "eq", "eq") validate.RegisterAlias("okkey", "eq=testkey|eq=testkeyok") type Test2 struct { Test1 map[string]string `validate:"gt=0,dive,keys,okkey,endkeys,eq=testval" json:"test1"` } var tst2 Test2 err = validate.Struct(tst2) NotEqual(t, err, nil) Equal(t, len(err.(ValidationErrors)), 1) AssertError(t, err.(ValidationErrors), "Test2.Test1", "Test2.Test1", "Test1", "Test1", "gt") tst2.Test1 = map[string]string{ "testkey": "testval", } err = validate.Struct(tst2) Equal(t, err, nil) tst2.Test1["badtestkey"] = "badtestval" err = validate.Struct(tst2) NotEqual(t, err, nil) errs = err.(ValidationErrors) Equal(t, len(errs), 2) AssertDeepError(t, errs, "Test2.Test1[badtestkey]", "Test2.Test1[badtestkey]", "Test1[badtestkey]", "Test1[badtestkey]", "okkey", "eq=testkey|eq=testkeyok") AssertDeepError(t, errs, "Test2.Test1[badtestkey]", "Test2.Test1[badtestkey]", "Test1[badtestkey]", "Test1[badtestkey]", "eq", "eq") } func TestStructLevelValidationsPointerPassing(t *testing.T) { v1 := New() v1.RegisterStructValidation(StructValidationTestStruct, &TestStruct{}) tst := &TestStruct{ String: "good value", } errs := v1.Struct(tst) NotEqual(t, errs, nil) AssertError(t, errs, "TestStruct.StringVal", "TestStruct.String", "StringVal", "String", "badvalueteststruct") } func TestDirValidation(t *testing.T) { validate := New() tests := []struct { title string param string expected bool }{ {"existing dir", "testdata", true}, {"existing self dir", ".", true}, {"existing parent dir", "..", true}, {"empty dir", "", false}, {"missing dir", "non_existing_testdata", false}, {"a file not a directory", filepath.Join("testdata", "a.go"), false}, } for _, test := range tests { errs := validate.Var(test.param, "dir") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Test: '%s' failed Error: %s", test.title, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Test: '%s' failed Error: %s", test.title, errs) } } } PanicMatches(t, func() { _ = validate.Var(2, "dir") }, "Bad field type int") } func TestStartsWithValidation(t *testing.T) { tests := []struct { Value string `validate:"startswith=(/^ヮ^)/*:・゚✧"` Tag string ExpectedNil bool }{ {Value: "(/^ヮ^)/*:・゚✧ glitter", Tag: "startswith=(/^ヮ^)/*:・゚✧", ExpectedNil: true}, {Value: "abcd", Tag: "startswith=(/^ヮ^)/*:・゚✧", ExpectedNil: false}, } validate := New() for i, s := range tests { errs := validate.Var(s.Value, s.Tag) if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { t.Fatalf("Index: %d failed Error: %s", i, errs) } errs = validate.Struct(s) if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { t.Fatalf("Index: %d failed Error: %s", i, errs) } } } func TestEndsWithValidation(t *testing.T) { tests := []struct { Value string `validate:"endswith=(/^ヮ^)/*:・゚✧"` Tag string ExpectedNil bool }{ {Value: "glitter (/^ヮ^)/*:・゚✧", Tag: "endswith=(/^ヮ^)/*:・゚✧", ExpectedNil: true}, {Value: "(/^ヮ^)/*:・゚✧ glitter", Tag: "endswith=(/^ヮ^)/*:・゚✧", ExpectedNil: false}, } validate := New() for i, s := range tests { errs := validate.Var(s.Value, s.Tag) if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { t.Fatalf("Index: %d failed Error: %s", i, errs) } errs = validate.Struct(s) if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { t.Fatalf("Index: %d failed Error: %s", i, errs) } } } func TestRequiredIf(t *testing.T) { type Inner struct { Field *string } fieldVal := "test" test := struct { Inner *Inner FieldE string `validate:"omitempty" json:"field_e"` FieldER string `validate:"required_if=FieldE test" json:"field_er"` Field1 string `validate:"omitempty" json:"field_1"` Field2 *string `validate:"required_if=Field1 test" json:"field_2"` Field3 map[string]string `validate:"required_if=Field2 test" json:"field_3"` Field4 interface{} `validate:"required_if=Field3 1" json:"field_4"` Field5 int `validate:"required_if=Inner.Field test" json:"field_5"` Field6 uint `validate:"required_if=Field5 1" json:"field_6"` Field7 float32 `validate:"required_if=Field6 1" json:"field_7"` Field8 float64 `validate:"required_if=Field7 1.0" json:"field_8"` }{ Inner: &Inner{Field: &fieldVal}, Field2: &fieldVal, Field3: map[string]string{"key": "val"}, Field4: "test", Field5: 2, } validate := New() errs := validate.Struct(test) Equal(t, errs, nil) test2 := struct { Inner *Inner Inner2 *Inner FieldE string `validate:"omitempty" json:"field_e"` FieldER string `validate:"required_if=FieldE test" json:"field_er"` Field1 string `validate:"omitempty" json:"field_1"` Field2 *string `validate:"required_if=Field1 test" json:"field_2"` Field3 map[string]string `validate:"required_if=Field2 test" json:"field_3"` Field4 interface{} `validate:"required_if=Field2 test" json:"field_4"` Field5 string `validate:"required_if=Field3 1" json:"field_5"` Field6 string `validate:"required_if=Inner.Field test" json:"field_6"` Field7 string `validate:"required_if=Inner2.Field test" json:"field_7"` }{ Inner: &Inner{Field: &fieldVal}, Field2: &fieldVal, } errs = validate.Struct(test2) NotEqual(t, errs, nil) ve := errs.(ValidationErrors) Equal(t, len(ve), 3) AssertError(t, errs, "Field3", "Field3", "Field3", "Field3", "required_if") AssertError(t, errs, "Field4", "Field4", "Field4", "Field4", "required_if") AssertError(t, errs, "Field6", "Field6", "Field6", "Field6", "required_if") defer func() { if r := recover(); r == nil { t.Errorf("test3 should have panicked!") } }() test3 := struct { Inner *Inner Field1 string `validate:"required_if=Inner.Field" json:"field_1"` }{ Inner: &Inner{Field: &fieldVal}, } _ = validate.Struct(test3) } func TestRequiredUnless(t *testing.T) { type Inner struct { Field *string } fieldVal := "test" test := struct { Inner *Inner FieldE string `validate:"omitempty" json:"field_e"` FieldER string `validate:"required_unless=FieldE test" json:"field_er"` Field1 string `validate:"omitempty" json:"field_1"` Field2 *string `validate:"required_unless=Field1 test" json:"field_2"` Field3 map[string]string `validate:"required_unless=Field2 test" json:"field_3"` Field4 interface{} `validate:"required_unless=Field3 1" json:"field_4"` Field5 int `validate:"required_unless=Inner.Field test" json:"field_5"` Field6 uint `validate:"required_unless=Field5 2" json:"field_6"` Field7 float32 `validate:"required_unless=Field6 0" json:"field_7"` Field8 float64 `validate:"required_unless=Field7 0.0" json:"field_8"` }{ FieldE: "test", Field2: &fieldVal, Field3: map[string]string{"key": "val"}, Field4: "test", Field5: 2, } validate := New() errs := validate.Struct(test) Equal(t, errs, nil) test2 := struct { Inner *Inner Inner2 *Inner FieldE string `validate:"omitempty" json:"field_e"` FieldER string `validate:"required_unless=FieldE test" json:"field_er"` Field1 string `validate:"omitempty" json:"field_1"` Field2 *string `validate:"required_unless=Field1 test" json:"field_2"` Field3 map[string]string `validate:"required_unless=Field2 test" json:"field_3"` Field4 interface{} `validate:"required_unless=Field2 test" json:"field_4"` Field5 string `validate:"required_unless=Field3 0" json:"field_5"` Field6 string `validate:"required_unless=Inner.Field test" json:"field_6"` Field7 string `validate:"required_unless=Inner2.Field test" json:"field_7"` }{ Inner: &Inner{Field: &fieldVal}, FieldE: "test", Field1: "test", } errs = validate.Struct(test2) NotEqual(t, errs, nil) ve := errs.(ValidationErrors) Equal(t, len(ve), 3) AssertError(t, errs, "Field3", "Field3", "Field3", "Field3", "required_unless") AssertError(t, errs, "Field4", "Field4", "Field4", "Field4", "required_unless") AssertError(t, errs, "Field7", "Field7", "Field7", "Field7", "required_unless") defer func() { if r := recover(); r == nil { t.Errorf("test3 should have panicked!") } }() test3 := struct { Inner *Inner Field1 string `validate:"required_unless=Inner.Field" json:"field_1"` }{ Inner: &Inner{Field: &fieldVal}, } _ = validate.Struct(test3) } func TestRequiredWith(t *testing.T) { type Inner struct { Field *string } fieldVal := "test" test := struct { Inner *Inner FieldE string `validate:"omitempty" json:"field_e"` FieldER string `validate:"required_with=FieldE" json:"field_er"` Field1 string `validate:"omitempty" json:"field_1"` Field2 *string `validate:"required_with=Field1" json:"field_2"` Field3 map[string]string `validate:"required_with=Field2" json:"field_3"` Field4 interface{} `validate:"required_with=Field3" json:"field_4"` Field5 string `validate:"required_with=Inner.Field" json:"field_5"` }{ Inner: &Inner{Field: &fieldVal}, Field2: &fieldVal, Field3: map[string]string{"key": "val"}, Field4: "test", Field5: "test", } validate := New() errs := validate.Struct(test) Equal(t, errs, nil) test2 := struct { Inner *Inner Inner2 *Inner FieldE string `validate:"omitempty" json:"field_e"` FieldER string `validate:"required_with=FieldE" json:"field_er"` Field1 string `validate:"omitempty" json:"field_1"` Field2 *string `validate:"required_with=Field1" json:"field_2"` Field3 map[string]string `validate:"required_with=Field2" json:"field_3"` Field4 interface{} `validate:"required_with=Field2" json:"field_4"` Field5 string `validate:"required_with=Field3" json:"field_5"` Field6 string `validate:"required_with=Inner.Field" json:"field_6"` Field7 string `validate:"required_with=Inner2.Field" json:"field_7"` }{ Inner: &Inner{Field: &fieldVal}, Field2: &fieldVal, } errs = validate.Struct(test2) NotEqual(t, errs, nil) ve := errs.(ValidationErrors) Equal(t, len(ve), 3) AssertError(t, errs, "Field3", "Field3", "Field3", "Field3", "required_with") AssertError(t, errs, "Field4", "Field4", "Field4", "Field4", "required_with") AssertError(t, errs, "Field6", "Field6", "Field6", "Field6", "required_with") } func TestExcludedWith(t *testing.T) { type Inner struct { FieldE string Field *string } fieldVal := "test" test := struct { Inner *Inner Inner2 *Inner Field string `validate:"omitempty" json:"field"` FieldE string `validate:"omitempty" json:"field_e"` Field1 string `validate:"excluded_with=FieldE" json:"field_1"` Field2 *string `validate:"excluded_with=FieldE" json:"field_2"` Field3 map[string]string `validate:"excluded_with=FieldE" json:"field_3"` Field4 interface{} `validate:"excluded_with=FieldE" json:"field_4"` Field5 string `validate:"excluded_with=Inner.FieldE" json:"field_5"` Field6 string `validate:"excluded_with=Inner2.FieldE" json:"field_6"` }{ Inner: &Inner{Field: &fieldVal}, Field1: fieldVal, Field2: &fieldVal, Field3: map[string]string{"key": "val"}, Field4: "test", Field5: "test", Field6: "test", } validate := New() errs := validate.Struct(test) Equal(t, errs, nil) test2 := struct { Inner *Inner Inner2 *Inner Field string `validate:"omitempty" json:"field"` FieldE string `validate:"omitempty" json:"field_e"` Field1 string `validate:"excluded_with=Field" json:"field_1"` Field2 *string `validate:"excluded_with=Field" json:"field_2"` Field3 map[string]string `validate:"excluded_with=Field" json:"field_3"` Field4 interface{} `validate:"excluded_with=Field" json:"field_4"` Field5 string `validate:"excluded_with=Inner.Field" json:"field_5"` Field6 string `validate:"excluded_with=Inner2.Field" json:"field_6"` }{ Inner: &Inner{Field: &fieldVal}, Field: "populated", Field1: fieldVal, Field2: &fieldVal, Field3: map[string]string{"key": "val"}, Field4: "test", Field5: "test", Field6: "test", } errs = validate.Struct(test2) NotEqual(t, errs, nil) ve := errs.(ValidationErrors) Equal(t, len(ve), 5) for i := 1; i <= 5; i++ { name := fmt.Sprintf("Field%d", i) AssertError(t, errs, name, name, name, name, "excluded_with") } } func TestExcludedWithout(t *testing.T) { type Inner struct { FieldE string Field *string } fieldVal := "test" test := struct { Inner *Inner Inner2 *Inner Field string `validate:"omitempty" json:"field"` FieldE string `validate:"omitempty" json:"field_e"` Field1 string `validate:"excluded_without=Field" json:"field_1"` Field2 *string `validate:"excluded_without=Field" json:"field_2"` Field3 map[string]string `validate:"excluded_without=Field" json:"field_3"` Field4 interface{} `validate:"excluded_without=Field" json:"field_4"` Field5 string `validate:"excluded_without=Inner.Field" json:"field_5"` }{ Inner: &Inner{Field: &fieldVal}, Field: "populated", Field1: fieldVal, Field2: &fieldVal, Field3: map[string]string{"key": "val"}, Field4: "test", Field5: "test", } validate := New() errs := validate.Struct(test) Equal(t, errs, nil) test2 := struct { Inner *Inner Inner2 *Inner Field string `validate:"omitempty" json:"field"` FieldE string `validate:"omitempty" json:"field_e"` Field1 string `validate:"excluded_without=FieldE" json:"field_1"` Field2 *string `validate:"excluded_without=FieldE" json:"field_2"` Field3 map[string]string `validate:"excluded_without=FieldE" json:"field_3"` Field4 interface{} `validate:"excluded_without=FieldE" json:"field_4"` Field5 string `validate:"excluded_without=Inner.FieldE" json:"field_5"` Field6 string `validate:"excluded_without=Inner2.FieldE" json:"field_6"` }{ Inner: &Inner{Field: &fieldVal}, Field1: fieldVal, Field2: &fieldVal, Field3: map[string]string{"key": "val"}, Field4: "test", Field5: "test", Field6: "test", } errs = validate.Struct(test2) NotEqual(t, errs, nil) ve := errs.(ValidationErrors) Equal(t, len(ve), 6) for i := 1; i <= 6; i++ { name := fmt.Sprintf("Field%d", i) AssertError(t, errs, name, name, name, name, "excluded_without") } } func TestExcludedWithAll(t *testing.T) { type Inner struct { FieldE string Field *string } fieldVal := "test" test := struct { Inner *Inner Inner2 *Inner Field string `validate:"omitempty" json:"field"` FieldE string `validate:"omitempty" json:"field_e"` Field1 string `validate:"excluded_with_all=FieldE Field" json:"field_1"` Field2 *string `validate:"excluded_with_all=FieldE Field" json:"field_2"` Field3 map[string]string `validate:"excluded_with_all=FieldE Field" json:"field_3"` Field4 interface{} `validate:"excluded_with_all=FieldE Field" json:"field_4"` Field5 string `validate:"excluded_with_all=Inner.FieldE" json:"field_5"` Field6 string `validate:"excluded_with_all=Inner2.FieldE" json:"field_6"` }{ Inner: &Inner{Field: &fieldVal}, Field: fieldVal, Field1: fieldVal, Field2: &fieldVal, Field3: map[string]string{"key": "val"}, Field4: "test", Field5: "test", Field6: "test", } validate := New() errs := validate.Struct(test) Equal(t, errs, nil) test2 := struct { Inner *Inner Inner2 *Inner Field string `validate:"omitempty" json:"field"` FieldE string `validate:"omitempty" json:"field_e"` Field1 string `validate:"excluded_with_all=Field FieldE" json:"field_1"` Field2 *string `validate:"excluded_with_all=Field FieldE" json:"field_2"` Field3 map[string]string `validate:"excluded_with_all=Field FieldE" json:"field_3"` Field4 interface{} `validate:"excluded_with_all=Field FieldE" json:"field_4"` Field5 string `validate:"excluded_with_all=Inner.Field" json:"field_5"` Field6 string `validate:"excluded_with_all=Inner2.Field" json:"field_6"` }{ Inner: &Inner{Field: &fieldVal}, Field: "populated", FieldE: "populated", Field1: fieldVal, Field2: &fieldVal, Field3: map[string]string{"key": "val"}, Field4: "test", Field5: "test", Field6: "test", } errs = validate.Struct(test2) NotEqual(t, errs, nil) ve := errs.(ValidationErrors) Equal(t, len(ve), 5) for i := 1; i <= 5; i++ { name := fmt.Sprintf("Field%d", i) AssertError(t, errs, name, name, name, name, "excluded_with_all") } } func TestExcludedWithoutAll(t *testing.T) { type Inner struct { FieldE string Field *string } fieldVal := "test" test := struct { Inner *Inner Inner2 *Inner Field string `validate:"omitempty" json:"field"` FieldE string `validate:"omitempty" json:"field_e"` Field1 string `validate:"excluded_without_all=Field FieldE" json:"field_1"` Field2 *string `validate:"excluded_without_all=Field FieldE" json:"field_2"` Field3 map[string]string `validate:"excluded_without_all=Field FieldE" json:"field_3"` Field4 interface{} `validate:"excluded_without_all=Field FieldE" json:"field_4"` Field5 string `validate:"excluded_without_all=Inner.Field Inner.Field2" json:"field_5"` }{ Inner: &Inner{Field: &fieldVal}, Field: "populated", Field1: fieldVal, Field2: &fieldVal, Field3: map[string]string{"key": "val"}, Field4: "test", Field5: "test", } validate := New() errs := validate.Struct(test) Equal(t, errs, nil) test2 := struct { Inner *Inner Inner2 *Inner Field string `validate:"omitempty" json:"field"` FieldE string `validate:"omitempty" json:"field_e"` Field1 string `validate:"excluded_without_all=FieldE Field" json:"field_1"` Field2 *string `validate:"excluded_without_all=FieldE Field" json:"field_2"` Field3 map[string]string `validate:"excluded_without_all=FieldE Field" json:"field_3"` Field4 interface{} `validate:"excluded_without_all=FieldE Field" json:"field_4"` Field5 string `validate:"excluded_without_all=Inner.FieldE" json:"field_5"` Field6 string `validate:"excluded_without_all=Inner2.FieldE" json:"field_6"` }{ Inner: &Inner{Field: &fieldVal}, Field1: fieldVal, Field2: &fieldVal, Field3: map[string]string{"key": "val"}, Field4: "test", Field5: "test", Field6: "test", } errs = validate.Struct(test2) NotEqual(t, errs, nil) ve := errs.(ValidationErrors) Equal(t, len(ve), 6) for i := 1; i <= 6; i++ { name := fmt.Sprintf("Field%d", i) AssertError(t, errs, name, name, name, name, "excluded_without_all") } } func TestRequiredWithAll(t *testing.T) { type Inner struct { Field *string } fieldVal := "test" test := struct { Inner *Inner FieldE string `validate:"omitempty" json:"field_e"` FieldER string `validate:"required_with_all=FieldE" json:"field_er"` Field1 string `validate:"omitempty" json:"field_1"` Field2 *string `validate:"required_with_all=Field1" json:"field_2"` Field3 map[string]string `validate:"required_with_all=Field2" json:"field_3"` Field4 interface{} `validate:"required_with_all=Field3" json:"field_4"` Field5 string `validate:"required_with_all=Inner.Field" json:"field_5"` }{ Inner: &Inner{Field: &fieldVal}, Field1: "test_field1", Field2: &fieldVal, Field3: map[string]string{"key": "val"}, Field4: "test", Field5: "test", } validate := New() errs := validate.Struct(test) Equal(t, errs, nil) test2 := struct { Inner *Inner Inner2 *Inner FieldE string `validate:"omitempty" json:"field_e"` FieldER string `validate:"required_with_all=FieldE" json:"field_er"` Field1 string `validate:"omitempty" json:"field_1"` Field2 *string `validate:"required_with_all=Field1" json:"field_2"` Field3 map[string]string `validate:"required_with_all=Field2" json:"field_3"` Field4 interface{} `validate:"required_with_all=Field1 FieldE" json:"field_4"` Field5 string `validate:"required_with_all=Inner.Field Field2" json:"field_5"` Field6 string `validate:"required_with_all=Inner2.Field Field2" json:"field_6"` }{ Inner: &Inner{Field: &fieldVal}, Field2: &fieldVal, } errs = validate.Struct(test2) NotEqual(t, errs, nil) ve := errs.(ValidationErrors) Equal(t, len(ve), 2) AssertError(t, errs, "Field3", "Field3", "Field3", "Field3", "required_with_all") AssertError(t, errs, "Field5", "Field5", "Field5", "Field5", "required_with_all") } func TestRequiredWithout(t *testing.T) { type Inner struct { Field *string } fieldVal := "test" test := struct { Inner *Inner Field1 string `validate:"omitempty" json:"field_1"` Field2 *string `validate:"required_without=Field1" json:"field_2"` Field3 map[string]string `validate:"required_without=Field2" json:"field_3"` Field4 interface{} `validate:"required_without=Field3" json:"field_4"` Field5 string `validate:"required_without=Field3" json:"field_5"` }{ Inner: &Inner{Field: &fieldVal}, Field2: &fieldVal, Field3: map[string]string{"key": "val"}, Field4: "test", Field5: "test", } validate := New() errs := validate.Struct(test) Equal(t, errs, nil) test2 := struct { Inner *Inner Inner2 *Inner Field1 string `json:"field_1"` Field2 *string `validate:"required_without=Field1" json:"field_2"` Field3 map[string]string `validate:"required_without=Field2" json:"field_3"` Field4 interface{} `validate:"required_without=Field3" json:"field_4"` Field5 string `validate:"required_without=Field3" json:"field_5"` Field6 string `validate:"required_without=Field1" json:"field_6"` Field7 string `validate:"required_without=Inner.Field" json:"field_7"` Field8 string `validate:"required_without=Inner.Field" json:"field_8"` }{ Inner: &Inner{}, Field3: map[string]string{"key": "val"}, Field4: "test", Field5: "test", } errs = validate.Struct(&test2) NotEqual(t, errs, nil) ve := errs.(ValidationErrors) Equal(t, len(ve), 4) AssertError(t, errs, "Field2", "Field2", "Field2", "Field2", "required_without") AssertError(t, errs, "Field6", "Field6", "Field6", "Field6", "required_without") AssertError(t, errs, "Field7", "Field7", "Field7", "Field7", "required_without") AssertError(t, errs, "Field8", "Field8", "Field8", "Field8", "required_without") test3 := struct { Field1 *string `validate:"required_without=Field2,omitempty,min=1" json:"field_1"` Field2 *string `validate:"required_without=Field1,omitempty,min=1" json:"field_2"` }{ Field1: &fieldVal, } errs = validate.Struct(&test3) Equal(t, errs, nil) } func TestRequiredWithoutAll(t *testing.T) { fieldVal := "test" test := struct { Field1 string `validate:"omitempty" json:"field_1"` Field2 *string `validate:"required_without_all=Field1" json:"field_2"` Field3 map[string]string `validate:"required_without_all=Field2" json:"field_3"` Field4 interface{} `validate:"required_without_all=Field3" json:"field_4"` Field5 string `validate:"required_without_all=Field3" json:"field_5"` }{ Field1: "", Field2: &fieldVal, Field3: map[string]string{"key": "val"}, Field4: "test", Field5: "test", } validate := New() errs := validate.Struct(test) Equal(t, errs, nil) test2 := struct { Field1 string `validate:"omitempty" json:"field_1"` Field2 *string `validate:"required_without_all=Field1" json:"field_2"` Field3 map[string]string `validate:"required_without_all=Field2" json:"field_3"` Field4 interface{} `validate:"required_without_all=Field3" json:"field_4"` Field5 string `validate:"required_without_all=Field3" json:"field_5"` Field6 string `validate:"required_without_all=Field1 Field3" json:"field_6"` }{ Field3: map[string]string{"key": "val"}, Field4: "test", Field5: "test", } errs = validate.Struct(test2) NotEqual(t, errs, nil) ve := errs.(ValidationErrors) Equal(t, len(ve), 1) AssertError(t, errs, "Field2", "Field2", "Field2", "Field2", "required_without_all") } func TestLookup(t *testing.T) { type Lookup struct { FieldA *string `json:"fieldA,omitempty" validate:"required_without=FieldB"` FieldB *string `json:"fieldB,omitempty" validate:"required_without=FieldA"` } fieldAValue := "1232" lookup := Lookup{ FieldA: &fieldAValue, FieldB: nil, } Equal(t, New().Struct(lookup), nil) } func TestAbilityToValidateNils(t *testing.T) { type TestStruct struct { Test *string `validate:"nil"` } ts := TestStruct{} val := New() fn := func(fl FieldLevel) bool { return fl.Field().Kind() == reflect.Ptr && fl.Field().IsNil() } err := val.RegisterValidation("nil", fn, true) Equal(t, err, nil) errs := val.Struct(ts) Equal(t, errs, nil) str := "string" ts.Test = &str errs = val.Struct(ts) NotEqual(t, errs, nil) } func TestRequiredWithoutPointers(t *testing.T) { type Lookup struct { FieldA *bool `json:"fieldA,omitempty" validate:"required_without=FieldB"` FieldB *bool `json:"fieldB,omitempty" validate:"required_without=FieldA"` } b := true lookup := Lookup{ FieldA: &b, FieldB: nil, } val := New() errs := val.Struct(lookup) Equal(t, errs, nil) b = false lookup = Lookup{ FieldA: &b, FieldB: nil, } errs = val.Struct(lookup) Equal(t, errs, nil) } func TestRequiredWithoutAllPointers(t *testing.T) { type Lookup struct { FieldA *bool `json:"fieldA,omitempty" validate:"required_without_all=FieldB"` FieldB *bool `json:"fieldB,omitempty" validate:"required_without_all=FieldA"` } b := true lookup := Lookup{ FieldA: &b, FieldB: nil, } val := New() errs := val.Struct(lookup) Equal(t, errs, nil) b = false lookup = Lookup{ FieldA: &b, FieldB: nil, } errs = val.Struct(lookup) Equal(t, errs, nil) } func TestGetTag(t *testing.T) { var tag string type Test struct { String string `validate:"mytag"` } val := New() _ = val.RegisterValidation("mytag", func(fl FieldLevel) bool { tag = fl.GetTag() return true }) var test Test errs := val.Struct(test) Equal(t, errs, nil) Equal(t, tag, "mytag") } func TestJSONValidation(t *testing.T) { tests := []struct { param string expected bool }{ {`foo`, false}, {`}{`, false}, {`{]`, false}, {`{}`, true}, {`{"foo":"bar"}`, true}, {`{"foo":"bar","bar":{"baz":["qux"]}}`, true}, {`{"foo": 3 "bar": 4}`, false}, {`{"foo": 3 ,"bar": 4`, false}, {`{foo": 3, "bar": 4}`, false}, {`foo`, false}, {`1`, true}, {`true`, true}, {`null`, true}, {`"null"`, true}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "json") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d json failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d json failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "json" { t.Fatalf("Index: %d json failed Error: %s", i, errs) } } } } PanicMatches(t, func() { _ = validate.Var(2, "json") }, "Bad field type int") } func Test_hostnameport_validator(t *testing.T) { type Host struct { Addr string `validate:"hostname_port"` } type testInput struct { data string expected bool } testData := []testInput{ {"bad..domain.name:234", false}, {"extra.dot.com.", false}, {"localhost:1234", true}, {"192.168.1.1:1234", true}, {":1234", true}, {"domain.com:1334", true}, {"this.domain.com:234", true}, {"domain:75000", false}, {"missing.port", false}, } for _, td := range testData { h := Host{Addr: td.data} v := New() err := v.Struct(h) if td.expected != (err == nil) { t.Fatalf("Test failed for data: %v Error: %v", td.data, err) } } } func TestLowercaseValidation(t *testing.T) { tests := []struct { param string expected bool }{ {`abcdefg`, true}, {`Abcdefg`, false}, {"", false}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "lowercase") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d lowercase failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d lowercase failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "lowercase" { t.Fatalf("Index: %d lowercase failed Error: %s", i, errs) } } } } PanicMatches(t, func() { _ = validate.Var(2, "lowercase") }, "Bad field type int") } func TestUppercaseValidation(t *testing.T) { tests := []struct { param string expected bool }{ {`ABCDEFG`, true}, {`aBCDEFG`, false}, {"", false}, } validate := New() for i, test := range tests { errs := validate.Var(test.param, "uppercase") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d uppercase failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d uppercase failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "uppercase" { t.Fatalf("Index: %d uppercase failed Error: %s", i, errs) } } } } PanicMatches(t, func() { _ = validate.Var(2, "uppercase") }, "Bad field type int") } func TestDatetimeValidation(t *testing.T) { tests := []struct { value string `validate:"datetime=2006-01-02"` tag string expected bool }{ {"2008-02-01", `datetime=2006-01-02`, true}, {"2008-Feb-01", `datetime=2006-01-02`, false}, } validate := New() for i, test := range tests { errs := validate.Var(test.value, test.tag) if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d datetime failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d datetime failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "datetime" { t.Fatalf("Index: %d datetime failed Error: %s", i, errs) } } } } PanicMatches(t, func() { _ = validate.Var(2, "datetime") }, "Bad field type int") } func TestIsIso3166Alpha2Validation(t *testing.T) { tests := []struct { value string `validate:"iso3166_1_alpha2"` expected bool }{ {"PL", true}, {"POL", false}, {"AA", false}, } validate := New() for i, test := range tests { errs := validate.Var(test.value, "iso3166_1_alpha2") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d iso3166_1_alpha2 failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d iso3166_1_alpha2 failed Error: %s", i, errs) } } } } func TestIsIso3166Alpha3Validation(t *testing.T) { tests := []struct { value string `validate:"iso3166_1_alpha3"` expected bool }{ {"POL", true}, {"PL", false}, {"AAA", false}, } validate := New() for i, test := range tests { errs := validate.Var(test.value, "iso3166_1_alpha3") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d iso3166_1_alpha3 failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d iso3166_1_alpha3 failed Error: %s", i, errs) } } } } func TestIsIso3166AlphaNumericValidation(t *testing.T) { tests := []struct { value int expected bool }{ {248, true}, {0, false}, {1, false}, } validate := New() for i, test := range tests { errs := validate.Var(test.value, "iso3166_1_alpha_numeric") if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d iso3166_1_alpha_numeric failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d iso3166_1_alpha_numeric failed Error: %s", i, errs) } } } PanicMatches(t, func() { _ = validate.Var("1", "iso3166_1_alpha_numeric") }, "Bad field type string") } func TestTimeZoneValidation(t *testing.T) { tests := []struct { value string `validate:"timezone"` tag string expected bool }{ // systems may have different time zone database, some systems time zone are case insensitive {"America/New_York", `timezone`, true}, {"UTC", `timezone`, true}, {"", `timezone`, false}, {"Local", `timezone`, false}, {"Unknown", `timezone`, false}, } validate := New() for i, test := range tests { errs := validate.Var(test.value, test.tag) if test.expected { if !IsEqual(errs, nil) { t.Fatalf("Index: %d time zone failed Error: %s", i, errs) } } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d time zone failed Error: %s", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "timezone" { t.Fatalf("Index: %d time zone failed Error: %s", i, errs) } } } } PanicMatches(t, func() { _ = validate.Var(2, "timezone") }, "Bad field type int") } func TestDurationType(t *testing.T) { tests := []struct { name string s interface{} // struct success bool }{ { name: "valid duration string pass", s: struct { Value time.Duration `validate:"gte=500ns"` }{ Value: time.Second, }, success: true, }, { name: "valid duration int pass", s: struct { Value time.Duration `validate:"gte=500"` }{ Value: time.Second, }, success: true, }, } validate := New() for _, tc := range tests { tc := tc t.Run(tc.name, func(t *testing.T) { t.Parallel() errs := validate.Struct(tc.s) if tc.success { Equal(t, errs, nil) return } NotEqual(t, errs, nil) }) } }