Import upstream version 10.6.1
Debian Janitor
2 years ago
0 | * @go-playground/validator-maintainers⏎ |
1 | 1 | |
2 | 2 | ## Quality Standard |
3 | 3 | |
4 | 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. | |
4 | To ensure the continued stability of this package, tests are required that cover the change in order for a pull request to be merged. | |
5 | 5 | |
6 | 6 | ## Reporting issues |
7 | 7 |
0 | ### Package version eg. v8, v9: | |
0 | - [ ] I have looked at the documentation [here](https://pkg.go.dev/github.com/go-playground/validator/v10#section-documentation) first? | |
1 | - [ ] I have looked at the examples provided that may showcase my question [here](/_examples)? | |
2 | ||
3 | ### Package version eg. v9, v10: | |
1 | 4 | |
2 | 5 | |
3 | 6 |
0 | Fixes Or Enhances # . | |
0 | ## Fixes Or Enhances | |
1 | ||
1 | 2 | |
2 | 3 | **Make sure that you've checked the boxes below before you submit PR:** |
3 | 4 | - [ ] Tests exist or have been written that cover this particular change. |
4 | 5 | |
5 | Change Details: | |
6 | ||
7 | - | |
8 | - | |
9 | - | |
10 | ||
11 | ||
12 | @go-playground/admins⏎ | |
6 | @go-playground/validator-maintainers⏎ |
0 | on: | |
1 | push: | |
2 | branches: | |
3 | - master | |
4 | pull_request: | |
5 | name: Test | |
6 | jobs: | |
7 | test: | |
8 | strategy: | |
9 | matrix: | |
10 | go-version: [1.15.x, 1.16.x] | |
11 | os: [ubuntu-latest, macos-latest, windows-latest] | |
12 | runs-on: ${{ matrix.os }} | |
13 | steps: | |
14 | - name: Install Go | |
15 | uses: actions/setup-go@v2 | |
16 | with: | |
17 | go-version: ${{ matrix.go-version }} | |
18 | ||
19 | - name: Checkout code | |
20 | uses: actions/checkout@v2 | |
21 | ||
22 | - name: Restore Cache | |
23 | uses: actions/cache@v2 | |
24 | with: | |
25 | path: ~/go/pkg/mod | |
26 | key: ${{ runner.os }}-v1-go-${{ hashFiles('**/go.sum') }} | |
27 | restore-keys: | | |
28 | ${{ runner.os }}-v1-go- | |
29 | ||
30 | - name: Test | |
31 | run: go test -race -covermode=atomic -coverprofile="profile.cov" ./... | |
32 | ||
33 | - name: Send Coverage | |
34 | if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.16.x' | |
35 | uses: shogo82148/actions-goveralls@v1 | |
36 | with: | |
37 | path-to-profile: profile.cov | |
38 | ||
39 | golangci: | |
40 | name: lint | |
41 | runs-on: ubuntu-latest | |
42 | steps: | |
43 | - uses: actions/checkout@v2 | |
44 | - name: golangci-lint | |
45 | uses: golangci/golangci-lint-action@v2 | |
46 | with: | |
47 | version: v1.39 |
0 | language: go | |
1 | go: | |
2 | - 1.15.2 | |
3 | - tip | |
4 | matrix: | |
5 | allow_failures: | |
6 | - go: tip | |
7 | ||
8 | notifications: | |
9 | email: | |
10 | recipients: dean.karn@gmail.com | |
11 | on_success: change | |
12 | on_failure: always | |
13 | ||
14 | before_install: | |
15 | - go install github.com/mattn/goveralls | |
16 | - mkdir -p $GOPATH/src/gopkg.in | |
17 | - ln -s $GOPATH/src/github.com/$TRAVIS_REPO_SLUG $GOPATH/src/gopkg.in/validator.v9 | |
18 | ||
19 | # Only clone the most recent commit. | |
20 | git: | |
21 | depth: 1 | |
22 | ||
23 | script: | |
24 | - go test -v -race -covermode=atomic -coverprofile=coverage.coverprofile ./... | |
25 | ||
26 | after_success: | | |
27 | [ $TRAVIS_GO_VERSION = 1.15.2 ] && | |
28 | goveralls -coverprofile=coverage.coverprofile -service travis-ci -repotoken $COVERALLS_TOKEN |
0 | ## Maintainers Guide | |
1 | ||
2 | ### Semantic Versioning | |
3 | Semantic versioning as defined [here](https://semver.org) must be strictly adhered to. | |
4 | ||
5 | ### External Dependencies | |
6 | Any new external dependencies MUST: | |
7 | - Have a compatible LICENSE present. | |
8 | - Be actively maintained. | |
9 | - Be approved by @go-playground/admins | |
10 | ||
11 | ### PR Merge Requirements | |
12 | - Up-to-date branch. | |
13 | - Passing tests and linting. | |
14 | - CODEOWNERS approval. | |
15 | - Tests that cover both the Happy and Unhappy paths.⏎ |
2 | 2 | linters-install: |
3 | 3 | @golangci-lint --version >/dev/null 2>&1 || { \ |
4 | 4 | echo "installing linting tools..."; \ |
5 | curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s v1.21.0; \ | |
5 | curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s v1.39.0; \ | |
6 | 6 | } |
7 | 7 | |
8 | 8 | lint: linters-install |
9 | $(PWD)/bin/golangci-lint run | |
9 | golangci-lint run | |
10 | 10 | |
11 | 11 | test: |
12 | 12 | $(GOCMD) test -cover -race ./... |
0 | 0 | Package validator |
1 | ================ | |
1 | ================= | |
2 | 2 | <img align="right" src="https://raw.githubusercontent.com/go-playground/validator/v9/logo.png">[![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) |
3 | ![Project status](https://img.shields.io/badge/version-10.4.1-green.svg) | |
3 | ![Project status](https://img.shields.io/badge/version-10.6.1-green.svg) | |
4 | 4 | [![Build Status](https://travis-ci.org/go-playground/validator.svg?branch=master)](https://travis-ci.org/go-playground/validator) |
5 | 5 | [![Coverage Status](https://coveralls.io/repos/go-playground/validator/badge.svg?branch=master&service=github)](https://coveralls.io/github/go-playground/validator?branch=master) |
6 | 6 | [![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/validator)](https://goreportcard.com/report/github.com/go-playground/validator) |
26 | 26 | |
27 | 27 | Use go get. |
28 | 28 | |
29 | go get github.com/go-playground/validator/v10 | |
29 | go get github.com/go-playground/validator | |
30 | 30 | |
31 | 31 | Then import the validator package into your own code. |
32 | 32 | |
33 | import "github.com/go-playground/validator/v10" | |
33 | import "github.com/go-playground/validator" | |
34 | 34 | |
35 | 35 | Error Return Value |
36 | 36 | ------- |
52 | 52 | Usage and documentation |
53 | 53 | ------ |
54 | 54 | |
55 | Please see https://godoc.org/github.com/go-playground/validator for detailed usage docs. | |
55 | Please see https://pkg.go.dev/github.com/go-playground/validator/v10 for detailed usage docs. | |
56 | 56 | |
57 | 57 | ##### Examples: |
58 | 58 | |
294 | 294 | Make a pull request... |
295 | 295 | |
296 | 296 | License |
297 | ------ | |
297 | ------- | |
298 | 298 | Distributed under MIT License, please see license file within the code for more details. |
299 | ||
300 | Maintainers | |
301 | ----------- | |
302 | This project has grown large enough that more than one person is required to properly support the community. | |
303 | If you are interested in becoming a maintainer please reach out to me https://github.com/deankarn |
0 | package main | |
1 | ||
2 | import ( | |
3 | "fmt" | |
4 | "github.com/go-playground/validator/v10" | |
5 | ) | |
6 | ||
7 | var validate *validator.Validate | |
8 | ||
9 | func main() { | |
10 | validate = validator.New() | |
11 | ||
12 | validateMap() | |
13 | validateNestedMap() | |
14 | } | |
15 | ||
16 | func validateMap() { | |
17 | user := map[string]interface{}{"name": "Arshiya Kiani", "email": "zytel3301@gmail.com"} | |
18 | ||
19 | // Every rule will be applied to the item of the data that the offset of rule is pointing to. | |
20 | // So if you have a field "email": "omitempty,required,email", the validator will apply these | |
21 | // rules to offset of email in user data | |
22 | rules := map[string]interface{}{"name": "required,min=8,max=32", "email": "omitempty,required,email"} | |
23 | ||
24 | // ValidateMap will return map[string]error. | |
25 | // The offset of every item in errs is the name of invalid field and the value | |
26 | // is the message of error. If there was no error, ValidateMap method will | |
27 | // return an EMPTY map of errors, not nil. If you want to check that | |
28 | // if there was an error or not, you must check the length of the return value | |
29 | errs := validate.ValidateMap(user, rules) | |
30 | ||
31 | if len(errs) > 0 { | |
32 | fmt.Println(errs) | |
33 | // The user is invalid | |
34 | } | |
35 | ||
36 | // The user is valid | |
37 | } | |
38 | ||
39 | func validateNestedMap() { | |
40 | ||
41 | data := map[string]interface{}{ | |
42 | "name": "Arshiya Kiani", | |
43 | "email": "zytel3301@gmail.com", | |
44 | "details": map[string]interface{}{ | |
45 | "family_members": map[string]interface{}{ | |
46 | "father_name": "Micheal", | |
47 | "mother_name": "Hannah", | |
48 | }, | |
49 | "salary": "1000", | |
50 | }, | |
51 | } | |
52 | ||
53 | // Rules must be set as the structure as the data itself. If you want to dive into the | |
54 | // map, just declare its rules as a map | |
55 | rules := map[string]interface{}{ | |
56 | "name": "min=4,max=32", | |
57 | "email": "required,email", | |
58 | "details": map[string]interface{}{ | |
59 | "family_members": map[string]interface{}{ | |
60 | "father_name": "required,min=4,max=32", | |
61 | "mother_name": "required,min=4,max=32", | |
62 | }, | |
63 | "salary": "number", | |
64 | }, | |
65 | } | |
66 | ||
67 | if len(validate.ValidateMap(data, rules)) == 0 { | |
68 | // Data is valid | |
69 | } | |
70 | ||
71 | // Data is invalid | |
72 | } |
43 | 43 | |
44 | 44 | // register validation for 'User' |
45 | 45 | // NOTE: only have to register a non-pointer type for 'User', validator |
46 | // interanlly dereferences during it's type checks. | |
46 | // internally dereferences during it's type checks. | |
47 | 47 | validate.RegisterStructValidation(UserStructLevelValidation, User{}) |
48 | 48 | |
49 | 49 | // build 'User' info, normally posted data etc... |
17 | 17 | "unicode/utf8" |
18 | 18 | |
19 | 19 | "golang.org/x/crypto/sha3" |
20 | "golang.org/x/text/language" | |
20 | 21 | |
21 | 22 | urn "github.com/leodido/go-urn" |
22 | 23 | ) |
66 | 67 | // you can add, remove or even replace items to suite your needs, |
67 | 68 | // or even disregard and use your own map if so desired. |
68 | 69 | bakedInValidators = map[string]Func{ |
69 | "required": hasValue, | |
70 | "required_if": requiredIf, | |
71 | "required_unless": requiredUnless, | |
72 | "required_with": requiredWith, | |
73 | "required_with_all": requiredWithAll, | |
74 | "required_without": requiredWithout, | |
75 | "required_without_all": requiredWithoutAll, | |
76 | "excluded_with": excludedWith, | |
77 | "excluded_with_all": excludedWithAll, | |
78 | "excluded_without": excludedWithout, | |
79 | "excluded_without_all": excludedWithoutAll, | |
80 | "isdefault": isDefault, | |
81 | "len": hasLengthOf, | |
82 | "min": hasMinOf, | |
83 | "max": hasMaxOf, | |
84 | "eq": isEq, | |
85 | "ne": isNe, | |
86 | "lt": isLt, | |
87 | "lte": isLte, | |
88 | "gt": isGt, | |
89 | "gte": isGte, | |
90 | "eqfield": isEqField, | |
91 | "eqcsfield": isEqCrossStructField, | |
92 | "necsfield": isNeCrossStructField, | |
93 | "gtcsfield": isGtCrossStructField, | |
94 | "gtecsfield": isGteCrossStructField, | |
95 | "ltcsfield": isLtCrossStructField, | |
96 | "ltecsfield": isLteCrossStructField, | |
97 | "nefield": isNeField, | |
98 | "gtefield": isGteField, | |
99 | "gtfield": isGtField, | |
100 | "ltefield": isLteField, | |
101 | "ltfield": isLtField, | |
102 | "fieldcontains": fieldContains, | |
103 | "fieldexcludes": fieldExcludes, | |
104 | "alpha": isAlpha, | |
105 | "alphanum": isAlphanum, | |
106 | "alphaunicode": isAlphaUnicode, | |
107 | "alphanumunicode": isAlphanumUnicode, | |
108 | "numeric": isNumeric, | |
109 | "number": isNumber, | |
110 | "hexadecimal": isHexadecimal, | |
111 | "hexcolor": isHEXColor, | |
112 | "rgb": isRGB, | |
113 | "rgba": isRGBA, | |
114 | "hsl": isHSL, | |
115 | "hsla": isHSLA, | |
116 | "e164": isE164, | |
117 | "email": isEmail, | |
118 | "url": isURL, | |
119 | "uri": isURI, | |
120 | "urn_rfc2141": isUrnRFC2141, // RFC 2141 | |
121 | "file": isFile, | |
122 | "base64": isBase64, | |
123 | "base64url": isBase64URL, | |
124 | "contains": contains, | |
125 | "containsany": containsAny, | |
126 | "containsrune": containsRune, | |
127 | "excludes": excludes, | |
128 | "excludesall": excludesAll, | |
129 | "excludesrune": excludesRune, | |
130 | "startswith": startsWith, | |
131 | "endswith": endsWith, | |
132 | "startsnotwith": startsNotWith, | |
133 | "endsnotwith": endsNotWith, | |
134 | "isbn": isISBN, | |
135 | "isbn10": isISBN10, | |
136 | "isbn13": isISBN13, | |
137 | "eth_addr": isEthereumAddress, | |
138 | "btc_addr": isBitcoinAddress, | |
139 | "btc_addr_bech32": isBitcoinBech32Address, | |
140 | "uuid": isUUID, | |
141 | "uuid3": isUUID3, | |
142 | "uuid4": isUUID4, | |
143 | "uuid5": isUUID5, | |
144 | "uuid_rfc4122": isUUIDRFC4122, | |
145 | "uuid3_rfc4122": isUUID3RFC4122, | |
146 | "uuid4_rfc4122": isUUID4RFC4122, | |
147 | "uuid5_rfc4122": isUUID5RFC4122, | |
148 | "ascii": isASCII, | |
149 | "printascii": isPrintableASCII, | |
150 | "multibyte": hasMultiByteCharacter, | |
151 | "datauri": isDataURI, | |
152 | "latitude": isLatitude, | |
153 | "longitude": isLongitude, | |
154 | "ssn": isSSN, | |
155 | "ipv4": isIPv4, | |
156 | "ipv6": isIPv6, | |
157 | "ip": isIP, | |
158 | "cidrv4": isCIDRv4, | |
159 | "cidrv6": isCIDRv6, | |
160 | "cidr": isCIDR, | |
161 | "tcp4_addr": isTCP4AddrResolvable, | |
162 | "tcp6_addr": isTCP6AddrResolvable, | |
163 | "tcp_addr": isTCPAddrResolvable, | |
164 | "udp4_addr": isUDP4AddrResolvable, | |
165 | "udp6_addr": isUDP6AddrResolvable, | |
166 | "udp_addr": isUDPAddrResolvable, | |
167 | "ip4_addr": isIP4AddrResolvable, | |
168 | "ip6_addr": isIP6AddrResolvable, | |
169 | "ip_addr": isIPAddrResolvable, | |
170 | "unix_addr": isUnixAddrResolvable, | |
171 | "mac": isMAC, | |
172 | "hostname": isHostnameRFC952, // RFC 952 | |
173 | "hostname_rfc1123": isHostnameRFC1123, // RFC 1123 | |
174 | "fqdn": isFQDN, | |
175 | "unique": isUnique, | |
176 | "oneof": isOneOf, | |
177 | "html": isHTML, | |
178 | "html_encoded": isHTMLEncoded, | |
179 | "url_encoded": isURLEncoded, | |
180 | "dir": isDir, | |
181 | "json": isJSON, | |
182 | "hostname_port": isHostnamePort, | |
183 | "lowercase": isLowercase, | |
184 | "uppercase": isUppercase, | |
185 | "datetime": isDatetime, | |
186 | "timezone": isTimeZone, | |
187 | "iso3166_1_alpha2": isIso3166Alpha2, | |
188 | "iso3166_1_alpha3": isIso3166Alpha3, | |
189 | "iso3166_1_alpha_numeric": isIso3166AlphaNumeric, | |
70 | "required": hasValue, | |
71 | "required_if": requiredIf, | |
72 | "required_unless": requiredUnless, | |
73 | "required_with": requiredWith, | |
74 | "required_with_all": requiredWithAll, | |
75 | "required_without": requiredWithout, | |
76 | "required_without_all": requiredWithoutAll, | |
77 | "excluded_with": excludedWith, | |
78 | "excluded_with_all": excludedWithAll, | |
79 | "excluded_without": excludedWithout, | |
80 | "excluded_without_all": excludedWithoutAll, | |
81 | "isdefault": isDefault, | |
82 | "len": hasLengthOf, | |
83 | "min": hasMinOf, | |
84 | "max": hasMaxOf, | |
85 | "eq": isEq, | |
86 | "ne": isNe, | |
87 | "lt": isLt, | |
88 | "lte": isLte, | |
89 | "gt": isGt, | |
90 | "gte": isGte, | |
91 | "eqfield": isEqField, | |
92 | "eqcsfield": isEqCrossStructField, | |
93 | "necsfield": isNeCrossStructField, | |
94 | "gtcsfield": isGtCrossStructField, | |
95 | "gtecsfield": isGteCrossStructField, | |
96 | "ltcsfield": isLtCrossStructField, | |
97 | "ltecsfield": isLteCrossStructField, | |
98 | "nefield": isNeField, | |
99 | "gtefield": isGteField, | |
100 | "gtfield": isGtField, | |
101 | "ltefield": isLteField, | |
102 | "ltfield": isLtField, | |
103 | "fieldcontains": fieldContains, | |
104 | "fieldexcludes": fieldExcludes, | |
105 | "alpha": isAlpha, | |
106 | "alphanum": isAlphanum, | |
107 | "alphaunicode": isAlphaUnicode, | |
108 | "alphanumunicode": isAlphanumUnicode, | |
109 | "numeric": isNumeric, | |
110 | "number": isNumber, | |
111 | "hexadecimal": isHexadecimal, | |
112 | "hexcolor": isHEXColor, | |
113 | "rgb": isRGB, | |
114 | "rgba": isRGBA, | |
115 | "hsl": isHSL, | |
116 | "hsla": isHSLA, | |
117 | "e164": isE164, | |
118 | "email": isEmail, | |
119 | "url": isURL, | |
120 | "uri": isURI, | |
121 | "urn_rfc2141": isUrnRFC2141, // RFC 2141 | |
122 | "file": isFile, | |
123 | "base64": isBase64, | |
124 | "base64url": isBase64URL, | |
125 | "contains": contains, | |
126 | "containsany": containsAny, | |
127 | "containsrune": containsRune, | |
128 | "excludes": excludes, | |
129 | "excludesall": excludesAll, | |
130 | "excludesrune": excludesRune, | |
131 | "startswith": startsWith, | |
132 | "endswith": endsWith, | |
133 | "startsnotwith": startsNotWith, | |
134 | "endsnotwith": endsNotWith, | |
135 | "isbn": isISBN, | |
136 | "isbn10": isISBN10, | |
137 | "isbn13": isISBN13, | |
138 | "eth_addr": isEthereumAddress, | |
139 | "btc_addr": isBitcoinAddress, | |
140 | "btc_addr_bech32": isBitcoinBech32Address, | |
141 | "uuid": isUUID, | |
142 | "uuid3": isUUID3, | |
143 | "uuid4": isUUID4, | |
144 | "uuid5": isUUID5, | |
145 | "uuid_rfc4122": isUUIDRFC4122, | |
146 | "uuid3_rfc4122": isUUID3RFC4122, | |
147 | "uuid4_rfc4122": isUUID4RFC4122, | |
148 | "uuid5_rfc4122": isUUID5RFC4122, | |
149 | "ascii": isASCII, | |
150 | "printascii": isPrintableASCII, | |
151 | "multibyte": hasMultiByteCharacter, | |
152 | "datauri": isDataURI, | |
153 | "latitude": isLatitude, | |
154 | "longitude": isLongitude, | |
155 | "ssn": isSSN, | |
156 | "ipv4": isIPv4, | |
157 | "ipv6": isIPv6, | |
158 | "ip": isIP, | |
159 | "cidrv4": isCIDRv4, | |
160 | "cidrv6": isCIDRv6, | |
161 | "cidr": isCIDR, | |
162 | "tcp4_addr": isTCP4AddrResolvable, | |
163 | "tcp6_addr": isTCP6AddrResolvable, | |
164 | "tcp_addr": isTCPAddrResolvable, | |
165 | "udp4_addr": isUDP4AddrResolvable, | |
166 | "udp6_addr": isUDP6AddrResolvable, | |
167 | "udp_addr": isUDPAddrResolvable, | |
168 | "ip4_addr": isIP4AddrResolvable, | |
169 | "ip6_addr": isIP6AddrResolvable, | |
170 | "ip_addr": isIPAddrResolvable, | |
171 | "unix_addr": isUnixAddrResolvable, | |
172 | "mac": isMAC, | |
173 | "hostname": isHostnameRFC952, // RFC 952 | |
174 | "hostname_rfc1123": isHostnameRFC1123, // RFC 1123 | |
175 | "fqdn": isFQDN, | |
176 | "unique": isUnique, | |
177 | "oneof": isOneOf, | |
178 | "html": isHTML, | |
179 | "html_encoded": isHTMLEncoded, | |
180 | "url_encoded": isURLEncoded, | |
181 | "dir": isDir, | |
182 | "json": isJSON, | |
183 | "hostname_port": isHostnamePort, | |
184 | "lowercase": isLowercase, | |
185 | "uppercase": isUppercase, | |
186 | "datetime": isDatetime, | |
187 | "timezone": isTimeZone, | |
188 | "iso3166_1_alpha2": isIso3166Alpha2, | |
189 | "iso3166_1_alpha3": isIso3166Alpha3, | |
190 | "iso3166_1_alpha_numeric": isIso3166AlphaNumeric, | |
191 | "bcp47_language_tag": isBCP47LanguageTag, | |
192 | "postcode_iso3166_alpha2": isPostcodeByIso3166Alpha2, | |
193 | "postcode_iso3166_alpha2_field": isPostcodeByIso3166Alpha2Field, | |
194 | "bic": isIsoBicFormat, | |
190 | 195 | } |
191 | 196 | ) |
192 | 197 | |
546 | 551 | return false |
547 | 552 | } |
548 | 553 | |
549 | if ethaddressRegexUpper.MatchString(address) || ethAddressRegexLower.MatchString(address) { | |
554 | if ethAddressRegexUpper.MatchString(address) || ethAddressRegexLower.MatchString(address) { | |
550 | 555 | return true |
551 | 556 | } |
552 | 557 | |
790 | 795 | case reflect.Slice, reflect.Map, reflect.Array: |
791 | 796 | return int64(field.Len()) != int64(currentField.Len()) |
792 | 797 | |
798 | case reflect.Bool: | |
799 | return field.Bool() != currentField.Bool() | |
800 | ||
793 | 801 | case reflect.Struct: |
794 | 802 | |
795 | 803 | fieldType := field.Type() |
1032 | 1040 | case reflect.Slice, reflect.Map, reflect.Array: |
1033 | 1041 | return int64(topField.Len()) != int64(field.Len()) |
1034 | 1042 | |
1043 | case reflect.Bool: | |
1044 | return topField.Bool() != field.Bool() | |
1045 | ||
1035 | 1046 | case reflect.Struct: |
1036 | 1047 | |
1037 | 1048 | fieldType := field.Type() |
1079 | 1090 | case reflect.Slice, reflect.Map, reflect.Array: |
1080 | 1091 | return int64(topField.Len()) == int64(field.Len()) |
1081 | 1092 | |
1093 | case reflect.Bool: | |
1094 | return topField.Bool() == field.Bool() | |
1095 | ||
1082 | 1096 | case reflect.Struct: |
1083 | 1097 | |
1084 | 1098 | fieldType := field.Type() |
1126 | 1140 | case reflect.Slice, reflect.Map, reflect.Array: |
1127 | 1141 | return int64(field.Len()) == int64(currentField.Len()) |
1128 | 1142 | |
1143 | case reflect.Bool: | |
1144 | return field.Bool() == currentField.Bool() | |
1145 | ||
1129 | 1146 | case reflect.Struct: |
1130 | 1147 | |
1131 | 1148 | fieldType := field.Type() |
1187 | 1204 | } |
1188 | 1205 | |
1189 | 1206 | panic(fmt.Sprintf("Bad field type %T", field.Interface())) |
1207 | } | |
1208 | ||
1209 | // isPostcodeByIso3166Alpha2 validates by value which is country code in iso 3166 alpha 2 | |
1210 | // example: `postcode_iso3166_alpha2=US` | |
1211 | func isPostcodeByIso3166Alpha2(fl FieldLevel) bool { | |
1212 | field := fl.Field() | |
1213 | param := fl.Param() | |
1214 | ||
1215 | reg, found := postCodeRegexDict[param] | |
1216 | if !found { | |
1217 | return false | |
1218 | } | |
1219 | ||
1220 | return reg.MatchString(field.String()) | |
1221 | } | |
1222 | ||
1223 | // isPostcodeByIso3166Alpha2 validates by field which represents for a value of country code in iso 3166 alpha 2 | |
1224 | // example: `postcode_iso3166_alpha2_field=CountryCode` | |
1225 | func isPostcodeByIso3166Alpha2Field(fl FieldLevel) bool { | |
1226 | field := fl.Field() | |
1227 | params := parseOneOfParam2(fl.Param()) | |
1228 | ||
1229 | if len(params) != 1 { | |
1230 | return false | |
1231 | } | |
1232 | ||
1233 | currentField, kind, _, found := fl.GetStructFieldOKAdvanced2(fl.Parent(), params[0]) | |
1234 | if !found { | |
1235 | return false | |
1236 | } | |
1237 | ||
1238 | if kind != reflect.String { | |
1239 | panic(fmt.Sprintf("Bad field type %T", currentField.Interface())) | |
1240 | } | |
1241 | ||
1242 | reg, found := postCodeRegexDict[currentField.String()] | |
1243 | if !found { | |
1244 | return false | |
1245 | } | |
1246 | ||
1247 | return reg.MatchString(field.String()) | |
1190 | 1248 | } |
1191 | 1249 | |
1192 | 1250 | // IsBase64 is the validation function for validating if the current field's value is a valid base 64. |
1329 | 1387 | |
1330 | 1388 | // IsHEXColor is the validation function for validating if the current field's value is a valid HEX color. |
1331 | 1389 | func isHEXColor(fl FieldLevel) bool { |
1332 | return hexcolorRegex.MatchString(fl.Field().String()) | |
1390 | return hexColorRegex.MatchString(fl.Field().String()) | |
1333 | 1391 | } |
1334 | 1392 | |
1335 | 1393 | // IsHexadecimal is the validation function for validating if the current field's value is a valid hexadecimal. |
1440 | 1498 | |
1441 | 1499 | case reflect.Slice, reflect.Map, reflect.Array: |
1442 | 1500 | return int64(field.Len()) == asInt(value) |
1501 | ||
1502 | case reflect.Bool: | |
1503 | return field.Bool() == asBool(value) | |
1443 | 1504 | } |
1444 | 1505 | |
1445 | 1506 | // default reflect.String: |
1543 | 1604 | return true |
1544 | 1605 | } |
1545 | 1606 | |
1546 | // RequiredWithoutAll is the validation function | |
1607 | // ExcludedWithoutAll is the validation function | |
1547 | 1608 | // The field under validation must not be present or is empty when all of the other specified fields are not present. |
1548 | 1609 | func excludedWithoutAll(fl FieldLevel) bool { |
1549 | 1610 | params := parseOneOfParam2(fl.Param()) |
2282 | 2343 | } |
2283 | 2344 | return iso3166_1_alpha_numeric[code] |
2284 | 2345 | } |
2346 | ||
2347 | // isBCP47LanguageTag is the validation function for validating if the current field's value is a valid BCP 47 language tag, as parsed by language.Parse | |
2348 | func isBCP47LanguageTag(fl FieldLevel) bool { | |
2349 | field := fl.Field() | |
2350 | ||
2351 | if field.Kind() == reflect.String { | |
2352 | _, err := language.Parse(field.String()) | |
2353 | return err == nil | |
2354 | } | |
2355 | ||
2356 | panic(fmt.Sprintf("Bad field type %T", field.Interface())) | |
2357 | } | |
2358 | ||
2359 | // isIsoBicFormat is the validation function for validating if the current field's value is a valid Business Identifier Code (SWIFT code), defined in ISO 9362 | |
2360 | func isIsoBicFormat(fl FieldLevel) bool { | |
2361 | bicString := fl.Field().String() | |
2362 | ||
2363 | return bicRegex.MatchString(bicString) | |
2364 | } |
1220 | 1220 | |
1221 | 1221 | Usage: iso3166_1_alpha3 |
1222 | 1222 | |
1223 | BCP 47 Language Tag | |
1224 | ||
1225 | This validates that a string value is a valid BCP 47 language tag, as parsed by language.Parse. | |
1226 | More information on https://pkg.go.dev/golang.org/x/text/language | |
1227 | ||
1228 | Usage: bcp47_language_tag | |
1229 | ||
1230 | BIC (SWIFT code) | |
1231 | ||
1232 | This validates that a string value is a valid Business Identifier Code (SWIFT code), defined in ISO 9362. | |
1233 | More information on https://www.iso.org/standard/60390.html | |
1234 | ||
1235 | Usage: bic | |
1236 | ||
1223 | 1237 | TimeZone |
1224 | 1238 | |
1225 | 1239 | This validates that a string value is a valid time zone based on the time zone database present on the system. |
1227 | 1241 | More information on https://golang.org/pkg/time/#LoadLocation |
1228 | 1242 | |
1229 | 1243 | Usage: timezone |
1230 | ||
1244 | ||
1231 | 1245 | |
1232 | 1246 | Alias Validators and Tags |
1233 | 1247 |
81 | 81 | // FieldError contains all functions to get error details |
82 | 82 | type FieldError interface { |
83 | 83 | |
84 | // returns the validation tag that failed. if the | |
84 | // Tag returns the validation tag that failed. if the | |
85 | 85 | // validation was an alias, this will return the |
86 | 86 | // alias name and not the underlying tag that failed. |
87 | 87 | // |
89 | 89 | // will return "iscolor" |
90 | 90 | Tag() string |
91 | 91 | |
92 | // returns the validation tag that failed, even if an | |
92 | // ActualTag returns the validation tag that failed, even if an | |
93 | 93 | // alias the actual tag within the alias will be returned. |
94 | 94 | // If an 'or' validation fails the entire or will be returned. |
95 | 95 | // |
97 | 97 | // will return "hexcolor|rgb|rgba|hsl|hsla" |
98 | 98 | ActualTag() string |
99 | 99 | |
100 | // returns the namespace for the field error, with the tag | |
100 | // Namespace returns the namespace for the field error, with the tag | |
101 | 101 | // name taking precedence over the field's actual name. |
102 | 102 | // |
103 | 103 | // eg. JSON name "User.fname" |
108 | 108 | // using validate.Field(...) as there is no way to extract it's name |
109 | 109 | Namespace() string |
110 | 110 | |
111 | // returns the namespace for the field error, with the field's | |
111 | // StructNamespace returns the namespace for the field error, with the field's | |
112 | 112 | // actual name. |
113 | 113 | // |
114 | 114 | // eq. "User.FirstName" see Namespace for comparison |
117 | 117 | // using validate.Field(...) as there is no way to extract its name |
118 | 118 | StructNamespace() string |
119 | 119 | |
120 | // returns the fields name with the tag name taking precedence over the | |
120 | // Field returns the fields name with the tag name taking precedence over the | |
121 | 121 | // field's actual name. |
122 | 122 | // |
123 | 123 | // eq. JSON name "fname" |
124 | 124 | // see StructField for comparison |
125 | 125 | Field() string |
126 | 126 | |
127 | // returns the field's actual name from the struct, when able to determine. | |
127 | // StructField returns the field's actual name from the struct, when able to determine. | |
128 | 128 | // |
129 | 129 | // eq. "FirstName" |
130 | 130 | // see Field for comparison |
131 | 131 | StructField() string |
132 | 132 | |
133 | // returns the actual field's value in case needed for creating the error | |
133 | // Value returns the actual field's value in case needed for creating the error | |
134 | 134 | // message |
135 | 135 | Value() interface{} |
136 | 136 | |
137 | // returns the param value, in string form for comparison; this will also | |
137 | // Param returns the param value, in string form for comparison; this will also | |
138 | 138 | // help with generating an error message |
139 | 139 | Param() string |
140 | 140 | |
145 | 145 | |
146 | 146 | // Type returns the Field's reflect Type |
147 | 147 | // |
148 | // // eg. time.Time's type is time.Time | |
148 | // eg. time.Time's type is time.Time | |
149 | 149 | Type() reflect.Type |
150 | 150 | |
151 | // returns the FieldError's translated error | |
151 | // Translate returns the FieldError's translated error | |
152 | 152 | // from the provided 'ut.Translator' and registered 'TranslationFunc' |
153 | 153 | // |
154 | 154 | // NOTE: if no registered translator can be found it returns the same as |
220 | 220 | // return fld |
221 | 221 | } |
222 | 222 | |
223 | // returns the field's actual name from the struct, when able to determine. | |
223 | // StructField returns the field's actual name from the struct, when able to determine. | |
224 | 224 | func (fe *fieldError) StructField() string { |
225 | 225 | // return fe.structField |
226 | 226 | return fe.structNs[len(fe.structNs)-int(fe.structfieldLen):] |
4 | 4 | // FieldLevel contains all the information and helper functions |
5 | 5 | // to validate a field |
6 | 6 | type FieldLevel interface { |
7 | // returns the top level struct, if any | |
7 | ||
8 | // Top returns the top level struct, if any | |
8 | 9 | Top() reflect.Value |
9 | 10 | |
10 | // returns the current fields parent struct, if any or | |
11 | // Parent returns the current fields parent struct, if any or | |
11 | 12 | // the comparison value if called 'VarWithValue' |
12 | 13 | Parent() reflect.Value |
13 | 14 | |
14 | // returns current field for validation | |
15 | // Field returns current field for validation | |
15 | 16 | Field() reflect.Value |
16 | 17 | |
17 | // returns the field's name with the tag | |
18 | // FieldName returns the field's name with the tag | |
18 | 19 | // name taking precedence over the fields actual name. |
19 | 20 | FieldName() string |
20 | 21 | |
21 | // returns the struct field's name | |
22 | // StructFieldName returns the struct field's name | |
22 | 23 | StructFieldName() string |
23 | 24 | |
24 | // returns param for validation against current field | |
25 | // Param returns param for validation against current field | |
25 | 26 | Param() string |
26 | 27 | |
27 | 28 | // GetTag returns the current validations tag name |
32 | 33 | // underlying value and it's kind. |
33 | 34 | ExtractType(field reflect.Value) (value reflect.Value, kind reflect.Kind, nullable bool) |
34 | 35 | |
35 | // traverses the parent struct to retrieve a specific field denoted by the provided namespace | |
36 | // GetStructFieldOK traverses the parent struct to retrieve a specific field denoted by the provided namespace | |
36 | 37 | // in the param and returns the field, field kind and whether is was successful in retrieving |
37 | 38 | // the field at all. |
38 | 39 | // |
48 | 49 | // Deprecated: Use GetStructFieldOKAdvanced2() instead which also return if the value is nullable. |
49 | 50 | GetStructFieldOKAdvanced(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool) |
50 | 51 | |
51 | // traverses the parent struct to retrieve a specific field denoted by the provided namespace | |
52 | // GetStructFieldOK2 traverses the parent struct to retrieve a specific field denoted by the provided namespace | |
52 | 53 | // in the param and returns the field, field kind, if it's a nullable type and whether is was successful in retrieving |
53 | 54 | // the field at all. |
54 | 55 | // |
56 | 57 | // could not be retrieved because it didn't exist. |
57 | 58 | GetStructFieldOK2() (reflect.Value, reflect.Kind, bool, bool) |
58 | 59 | |
59 | // GetStructFieldOKAdvanced is the same as GetStructFieldOK except that it accepts the parent struct to start looking for | |
60 | // GetStructFieldOKAdvanced2 is the same as GetStructFieldOK except that it accepts the parent struct to start looking for | |
60 | 61 | // the field and namespace allowing more extensibility for validators. |
61 | 62 | GetStructFieldOKAdvanced2(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool, bool) |
62 | 63 | } |
106 | 107 | return current, kind, found |
107 | 108 | } |
108 | 109 | |
109 | // GetStructFieldOK returns Param returns param for validation against current field | |
110 | // GetStructFieldOK2 returns Param returns param for validation against current field | |
110 | 111 | func (v *validate) GetStructFieldOK2() (reflect.Value, reflect.Kind, bool, bool) { |
111 | 112 | return v.getStructFieldOKInternal(v.slflParent, v.ct.param) |
112 | 113 | } |
113 | 114 | |
114 | // GetStructFieldOKAdvanced is the same as GetStructFieldOK except that it accepts the parent struct to start looking for | |
115 | // GetStructFieldOKAdvanced2 is the same as GetStructFieldOK except that it accepts the parent struct to start looking for | |
115 | 116 | // the field and namespace allowing more extensibility for validators. |
116 | 117 | func (v *validate) GetStructFieldOKAdvanced2(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool, bool) { |
117 | 118 | return v.getStructFieldOKInternal(val, namespace) |
7 | 7 | github.com/go-playground/universal-translator v0.17.0 |
8 | 8 | github.com/leodido/go-urn v1.2.0 |
9 | 9 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 |
10 | golang.org/x/text v0.3.2 // indirect | |
10 | 11 | ) |
9 | 9 | github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= |
10 | 10 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= |
11 | 11 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= |
12 | github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= | |
12 | 13 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= |
13 | 14 | github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= |
14 | 15 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= |
15 | 16 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= |
16 | 17 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= |
17 | 18 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= |
19 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ= | |
18 | 20 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= |
19 | 21 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
22 | golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= | |
20 | 23 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
21 | 24 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |
25 | golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= | |
22 | 26 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= |
27 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e h1:FDhOuMEY4JVRztM/gsbk+IKUQ8kj74bxZrgw87eMMVc= | |
23 | 28 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
24 | 29 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= |
25 | 30 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
0 | package validator | |
1 | ||
2 | import "regexp" | |
3 | ||
4 | var postCodePatternDict = map[string]string{ | |
5 | "GB": `^GIR[ ]?0AA|((AB|AL|B|BA|BB|BD|BH|BL|BN|BR|BS|BT|CA|CB|CF|CH|CM|CO|CR|CT|CV|CW|DA|DD|DE|DG|DH|DL|DN|DT|DY|E|EC|EH|EN|EX|FK|FY|G|GL|GY|GU|HA|HD|HG|HP|HR|HS|HU|HX|IG|IM|IP|IV|JE|KA|KT|KW|KY|L|LA|LD|LE|LL|LN|LS|LU|M|ME|MK|ML|N|NE|NG|NN|NP|NR|NW|OL|OX|PA|PE|PH|PL|PO|PR|RG|RH|RM|S|SA|SE|SG|SK|SL|SM|SN|SO|SP|SR|SS|ST|SW|SY|TA|TD|TF|TN|TQ|TR|TS|TW|UB|W|WA|WC|WD|WF|WN|WR|WS|WV|YO|ZE)(\d[\dA-Z]?[ ]?\d[ABD-HJLN-UW-Z]{2}))|BFPO[ ]?\d{1,4}$`, | |
6 | "JE": `^JE\d[\dA-Z]?[ ]?\d[ABD-HJLN-UW-Z]{2}$`, | |
7 | "GG": `^GY\d[\dA-Z]?[ ]?\d[ABD-HJLN-UW-Z]{2}$`, | |
8 | "IM": `^IM\d[\dA-Z]?[ ]?\d[ABD-HJLN-UW-Z]{2}$`, | |
9 | "US": `^\d{5}([ \-]\d{4})?$`, | |
10 | "CA": `^[ABCEGHJKLMNPRSTVXY]\d[ABCEGHJ-NPRSTV-Z][ ]?\d[ABCEGHJ-NPRSTV-Z]\d$`, | |
11 | "DE": `^\d{5}$`, | |
12 | "JP": `^\d{3}-\d{4}$`, | |
13 | "FR": `^\d{2}[ ]?\d{3}$`, | |
14 | "AU": `^\d{4}$`, | |
15 | "IT": `^\d{5}$`, | |
16 | "CH": `^\d{4}$`, | |
17 | "AT": `^\d{4}$`, | |
18 | "ES": `^\d{5}$`, | |
19 | "NL": `^\d{4}[ ]?[A-Z]{2}$`, | |
20 | "BE": `^\d{4}$`, | |
21 | "DK": `^\d{4}$`, | |
22 | "SE": `^\d{3}[ ]?\d{2}$`, | |
23 | "NO": `^\d{4}$`, | |
24 | "BR": `^\d{5}[\-]?\d{3}$`, | |
25 | "PT": `^\d{4}([\-]\d{3})?$`, | |
26 | "FI": `^\d{5}$`, | |
27 | "AX": `^22\d{3}$`, | |
28 | "KR": `^\d{3}[\-]\d{3}$`, | |
29 | "CN": `^\d{6}$`, | |
30 | "TW": `^\d{3}(\d{2})?$`, | |
31 | "SG": `^\d{6}$`, | |
32 | "DZ": `^\d{5}$`, | |
33 | "AD": `^AD\d{3}$`, | |
34 | "AR": `^([A-HJ-NP-Z])?\d{4}([A-Z]{3})?$`, | |
35 | "AM": `^(37)?\d{4}$`, | |
36 | "AZ": `^\d{4}$`, | |
37 | "BH": `^((1[0-2]|[2-9])\d{2})?$`, | |
38 | "BD": `^\d{4}$`, | |
39 | "BB": `^(BB\d{5})?$`, | |
40 | "BY": `^\d{6}$`, | |
41 | "BM": `^[A-Z]{2}[ ]?[A-Z0-9]{2}$`, | |
42 | "BA": `^\d{5}$`, | |
43 | "IO": `^BBND 1ZZ$`, | |
44 | "BN": `^[A-Z]{2}[ ]?\d{4}$`, | |
45 | "BG": `^\d{4}$`, | |
46 | "KH": `^\d{5}$`, | |
47 | "CV": `^\d{4}$`, | |
48 | "CL": `^\d{7}$`, | |
49 | "CR": `^\d{4,5}|\d{3}-\d{4}$`, | |
50 | "HR": `^\d{5}$`, | |
51 | "CY": `^\d{4}$`, | |
52 | "CZ": `^\d{3}[ ]?\d{2}$`, | |
53 | "DO": `^\d{5}$`, | |
54 | "EC": `^([A-Z]\d{4}[A-Z]|(?:[A-Z]{2})?\d{6})?$`, | |
55 | "EG": `^\d{5}$`, | |
56 | "EE": `^\d{5}$`, | |
57 | "FO": `^\d{3}$`, | |
58 | "GE": `^\d{4}$`, | |
59 | "GR": `^\d{3}[ ]?\d{2}$`, | |
60 | "GL": `^39\d{2}$`, | |
61 | "GT": `^\d{5}$`, | |
62 | "HT": `^\d{4}$`, | |
63 | "HN": `^(?:\d{5})?$`, | |
64 | "HU": `^\d{4}$`, | |
65 | "IS": `^\d{3}$`, | |
66 | "IN": `^\d{6}$`, | |
67 | "ID": `^\d{5}$`, | |
68 | "IL": `^\d{5}$`, | |
69 | "JO": `^\d{5}$`, | |
70 | "KZ": `^\d{6}$`, | |
71 | "KE": `^\d{5}$`, | |
72 | "KW": `^\d{5}$`, | |
73 | "LA": `^\d{5}$`, | |
74 | "LV": `^\d{4}$`, | |
75 | "LB": `^(\d{4}([ ]?\d{4})?)?$`, | |
76 | "LI": `^(948[5-9])|(949[0-7])$`, | |
77 | "LT": `^\d{5}$`, | |
78 | "LU": `^\d{4}$`, | |
79 | "MK": `^\d{4}$`, | |
80 | "MY": `^\d{5}$`, | |
81 | "MV": `^\d{5}$`, | |
82 | "MT": `^[A-Z]{3}[ ]?\d{2,4}$`, | |
83 | "MU": `^(\d{3}[A-Z]{2}\d{3})?$`, | |
84 | "MX": `^\d{5}$`, | |
85 | "MD": `^\d{4}$`, | |
86 | "MC": `^980\d{2}$`, | |
87 | "MA": `^\d{5}$`, | |
88 | "NP": `^\d{5}$`, | |
89 | "NZ": `^\d{4}$`, | |
90 | "NI": `^((\d{4}-)?\d{3}-\d{3}(-\d{1})?)?$`, | |
91 | "NG": `^(\d{6})?$`, | |
92 | "OM": `^(PC )?\d{3}$`, | |
93 | "PK": `^\d{5}$`, | |
94 | "PY": `^\d{4}$`, | |
95 | "PH": `^\d{4}$`, | |
96 | "PL": `^\d{2}-\d{3}$`, | |
97 | "PR": `^00[679]\d{2}([ \-]\d{4})?$`, | |
98 | "RO": `^\d{6}$`, | |
99 | "RU": `^\d{6}$`, | |
100 | "SM": `^4789\d$`, | |
101 | "SA": `^\d{5}$`, | |
102 | "SN": `^\d{5}$`, | |
103 | "SK": `^\d{3}[ ]?\d{2}$`, | |
104 | "SI": `^\d{4}$`, | |
105 | "ZA": `^\d{4}$`, | |
106 | "LK": `^\d{5}$`, | |
107 | "TJ": `^\d{6}$`, | |
108 | "TH": `^\d{5}$`, | |
109 | "TN": `^\d{4}$`, | |
110 | "TR": `^\d{5}$`, | |
111 | "TM": `^\d{6}$`, | |
112 | "UA": `^\d{5}$`, | |
113 | "UY": `^\d{5}$`, | |
114 | "UZ": `^\d{6}$`, | |
115 | "VA": `^00120$`, | |
116 | "VE": `^\d{4}$`, | |
117 | "ZM": `^\d{5}$`, | |
118 | "AS": `^96799$`, | |
119 | "CC": `^6799$`, | |
120 | "CK": `^\d{4}$`, | |
121 | "RS": `^\d{6}$`, | |
122 | "ME": `^8\d{4}$`, | |
123 | "CS": `^\d{5}$`, | |
124 | "YU": `^\d{5}$`, | |
125 | "CX": `^6798$`, | |
126 | "ET": `^\d{4}$`, | |
127 | "FK": `^FIQQ 1ZZ$`, | |
128 | "NF": `^2899$`, | |
129 | "FM": `^(9694[1-4])([ \-]\d{4})?$`, | |
130 | "GF": `^9[78]3\d{2}$`, | |
131 | "GN": `^\d{3}$`, | |
132 | "GP": `^9[78][01]\d{2}$`, | |
133 | "GS": `^SIQQ 1ZZ$`, | |
134 | "GU": `^969[123]\d([ \-]\d{4})?$`, | |
135 | "GW": `^\d{4}$`, | |
136 | "HM": `^\d{4}$`, | |
137 | "IQ": `^\d{5}$`, | |
138 | "KG": `^\d{6}$`, | |
139 | "LR": `^\d{4}$`, | |
140 | "LS": `^\d{3}$`, | |
141 | "MG": `^\d{3}$`, | |
142 | "MH": `^969[67]\d([ \-]\d{4})?$`, | |
143 | "MN": `^\d{6}$`, | |
144 | "MP": `^9695[012]([ \-]\d{4})?$`, | |
145 | "MQ": `^9[78]2\d{2}$`, | |
146 | "NC": `^988\d{2}$`, | |
147 | "NE": `^\d{4}$`, | |
148 | "VI": `^008(([0-4]\d)|(5[01]))([ \-]\d{4})?$`, | |
149 | "VN": `^[0-9]{1,6}$`, | |
150 | "PF": `^987\d{2}$`, | |
151 | "PG": `^\d{3}$`, | |
152 | "PM": `^9[78]5\d{2}$`, | |
153 | "PN": `^PCRN 1ZZ$`, | |
154 | "PW": `^96940$`, | |
155 | "RE": `^9[78]4\d{2}$`, | |
156 | "SH": `^(ASCN|STHL) 1ZZ$`, | |
157 | "SJ": `^\d{4}$`, | |
158 | "SO": `^\d{5}$`, | |
159 | "SZ": `^[HLMS]\d{3}$`, | |
160 | "TC": `^TKCA 1ZZ$`, | |
161 | "WF": `^986\d{2}$`, | |
162 | "XK": `^\d{5}$`, | |
163 | "YT": `^976\d{2}$`, | |
164 | } | |
165 | ||
166 | var postCodeRegexDict = map[string]*regexp.Regexp{} | |
167 | ||
168 | func init() { | |
169 | for countryCode, pattern := range postCodePatternDict { | |
170 | postCodeRegexDict[countryCode] = regexp.MustCompile(pattern) | |
171 | } | |
172 | } |
9 | 9 | numericRegexString = "^[-+]?[0-9]+(?:\\.[0-9]+)?$" |
10 | 10 | numberRegexString = "^[0-9]+$" |
11 | 11 | hexadecimalRegexString = "^(0[xX])?[0-9a-fA-F]+$" |
12 | hexcolorRegexString = "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$" | |
12 | hexColorRegexString = "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$" | |
13 | 13 | 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*\\)$" |
14 | 14 | 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*\\)$" |
15 | 15 | 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*\\)$" |
44 | 44 | ethAddressRegexString = `^0x[0-9a-fA-F]{40}$` |
45 | 45 | ethAddressUpperRegexString = `^0x[0-9A-F]{40}$` |
46 | 46 | ethAddressLowerRegexString = `^0x[0-9a-f]{40}$` |
47 | uRLEncodedRegexString = `(%[A-Fa-f0-9]{2})` | |
47 | uRLEncodedRegexString = `^(?:[^%]|%[0-9A-Fa-f]{2})*$` | |
48 | 48 | hTMLEncodedRegexString = `&#[x]?([0-9a-fA-F]{2})|(>)|(<)|(")|(&)+[;]?` |
49 | 49 | hTMLRegexString = `<[/]?([a-zA-Z]+).*?>` |
50 | 50 | splitParamsRegexString = `'[^']*'|\S+` |
51 | bicRegexString = `^[A-Za-z]{6}[A-Za-z0-9]{2}([A-Za-z0-9]{3})?$` | |
51 | 52 | ) |
52 | 53 | |
53 | 54 | var ( |
58 | 59 | numericRegex = regexp.MustCompile(numericRegexString) |
59 | 60 | numberRegex = regexp.MustCompile(numberRegexString) |
60 | 61 | hexadecimalRegex = regexp.MustCompile(hexadecimalRegexString) |
61 | hexcolorRegex = regexp.MustCompile(hexcolorRegexString) | |
62 | hexColorRegex = regexp.MustCompile(hexColorRegexString) | |
62 | 63 | rgbRegex = regexp.MustCompile(rgbRegexString) |
63 | 64 | rgbaRegex = regexp.MustCompile(rgbaRegexString) |
64 | 65 | hslRegex = regexp.MustCompile(hslRegexString) |
91 | 92 | btcUpperAddressRegexBech32 = regexp.MustCompile(btcAddressUpperRegexStringBech32) |
92 | 93 | btcLowerAddressRegexBech32 = regexp.MustCompile(btcAddressLowerRegexStringBech32) |
93 | 94 | ethAddressRegex = regexp.MustCompile(ethAddressRegexString) |
94 | ethaddressRegexUpper = regexp.MustCompile(ethAddressUpperRegexString) | |
95 | ethAddressRegexUpper = regexp.MustCompile(ethAddressUpperRegexString) | |
95 | 96 | ethAddressRegexLower = regexp.MustCompile(ethAddressLowerRegexString) |
96 | 97 | uRLEncodedRegex = regexp.MustCompile(uRLEncodedRegexString) |
97 | 98 | hTMLEncodedRegex = regexp.MustCompile(hTMLEncodedRegexString) |
98 | 99 | hTMLRegex = regexp.MustCompile(hTMLRegexString) |
99 | 100 | splitParamsRegex = regexp.MustCompile(splitParamsRegexString) |
101 | bicRegex = regexp.MustCompile(bicRegexString) | |
100 | 102 | ) |
22 | 22 | // to validate a struct |
23 | 23 | type StructLevel interface { |
24 | 24 | |
25 | // returns the main validation object, in case one wants to call validations internally. | |
25 | // Validator returns the main validation object, in case one wants to call validations internally. | |
26 | 26 | // this is so you don't have to use anonymous functions to get access to the validate |
27 | 27 | // instance. |
28 | 28 | Validator() *Validate |
29 | 29 | |
30 | // returns the top level struct, if any | |
30 | // Top returns the top level struct, if any | |
31 | 31 | Top() reflect.Value |
32 | 32 | |
33 | // returns the current fields parent struct, if any | |
33 | // Parent returns the current fields parent struct, if any | |
34 | 34 | Parent() reflect.Value |
35 | 35 | |
36 | // returns the current struct. | |
36 | // Current returns the current struct. | |
37 | 37 | Current() reflect.Value |
38 | 38 | |
39 | 39 | // ExtractType gets the actual underlying type of field value. |
41 | 41 | // underlying value and its kind. |
42 | 42 | ExtractType(field reflect.Value) (value reflect.Value, kind reflect.Kind, nullable bool) |
43 | 43 | |
44 | // reports an error just by passing the field and tag information | |
44 | // ReportError reports an error just by passing the field and tag information | |
45 | 45 | // |
46 | 46 | // NOTES: |
47 | 47 | // |
53 | 53 | // and process on the flip side it's up to you. |
54 | 54 | ReportError(field interface{}, fieldName, structFieldName string, tag, param string) |
55 | 55 | |
56 | // reports an error just by passing ValidationErrors | |
56 | // ReportValidationErrors reports an error just by passing ValidationErrors | |
57 | 57 | // |
58 | 58 | // NOTES: |
59 | 59 | // |
15 | 15 | // RegisterDefaultTranslations registers a set of default translations |
16 | 16 | // for all built in tag's in validator; you may add your own as desired. |
17 | 17 | func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (err error) { |
18 | ||
19 | 18 | translations := []struct { |
20 | 19 | tag string |
21 | 20 | translation string |
31 | 30 | { |
32 | 31 | tag: "len", |
33 | 32 | customRegisFunc: func(ut ut.Translator) (err error) { |
34 | ||
35 | 33 | if err = ut.Add("len-string", "{0} must be {1} in length", false); err != nil { |
36 | 34 | return |
37 | 35 | } |
60 | 58 | } |
61 | 59 | |
62 | 60 | return |
63 | ||
64 | }, | |
65 | customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { | |
66 | ||
61 | }, | |
62 | customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { | |
67 | 63 | var err error |
68 | 64 | var t string |
69 | 65 | |
122 | 118 | { |
123 | 119 | tag: "min", |
124 | 120 | customRegisFunc: func(ut ut.Translator) (err error) { |
125 | ||
126 | 121 | if err = ut.Add("min-string", "{0} must be at least {1} in length", false); err != nil { |
127 | 122 | return |
128 | 123 | } |
151 | 146 | } |
152 | 147 | |
153 | 148 | return |
154 | ||
155 | }, | |
156 | customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { | |
157 | ||
149 | }, | |
150 | customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { | |
158 | 151 | var err error |
159 | 152 | var t string |
160 | 153 | |
213 | 206 | { |
214 | 207 | tag: "max", |
215 | 208 | customRegisFunc: func(ut ut.Translator) (err error) { |
216 | ||
217 | 209 | if err = ut.Add("max-string", "{0} must be a maximum of {1} in length", false); err != nil { |
218 | 210 | return |
219 | 211 | } |
242 | 234 | } |
243 | 235 | |
244 | 236 | return |
245 | ||
246 | }, | |
247 | customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { | |
248 | ||
237 | }, | |
238 | customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { | |
249 | 239 | var err error |
250 | 240 | var t string |
251 | 241 | |
306 | 296 | translation: "{0} is not equal to {1}", |
307 | 297 | override: false, |
308 | 298 | customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { |
309 | ||
310 | 299 | t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) |
311 | 300 | if err != nil { |
312 | 301 | fmt.Printf("warning: error translating FieldError: %#v", fe) |
321 | 310 | translation: "{0} should not be equal to {1}", |
322 | 311 | override: false, |
323 | 312 | customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { |
324 | ||
325 | 313 | t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) |
326 | 314 | if err != nil { |
327 | 315 | fmt.Printf("warning: error translating FieldError: %#v", fe) |
334 | 322 | { |
335 | 323 | tag: "lt", |
336 | 324 | customRegisFunc: func(ut ut.Translator) (err error) { |
337 | ||
338 | 325 | if err = ut.Add("lt-string", "{0} must be less than {1} in length", false); err != nil { |
339 | 326 | return |
340 | 327 | } |
368 | 355 | } |
369 | 356 | |
370 | 357 | return |
371 | ||
372 | }, | |
373 | customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { | |
374 | ||
358 | }, | |
359 | customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { | |
375 | 360 | var err error |
376 | 361 | var t string |
377 | 362 | var f64 float64 |
379 | 364 | var kind reflect.Kind |
380 | 365 | |
381 | 366 | fn := func() (err error) { |
382 | ||
383 | 367 | if idx := strings.Index(fe.Param(), "."); idx != -1 { |
384 | 368 | digits = uint64(len(fe.Param()[idx+1:])) |
385 | 369 | } |
455 | 439 | { |
456 | 440 | tag: "lte", |
457 | 441 | customRegisFunc: func(ut ut.Translator) (err error) { |
458 | ||
459 | 442 | if err = ut.Add("lte-string", "{0} must be at maximum {1} in length", false); err != nil { |
460 | 443 | return |
461 | 444 | } |
491 | 474 | return |
492 | 475 | }, |
493 | 476 | customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { |
494 | ||
495 | 477 | var err error |
496 | 478 | var t string |
497 | 479 | var f64 float64 |
499 | 481 | var kind reflect.Kind |
500 | 482 | |
501 | 483 | fn := func() (err error) { |
502 | ||
503 | 484 | if idx := strings.Index(fe.Param(), "."); idx != -1 { |
504 | 485 | digits = uint64(len(fe.Param()[idx+1:])) |
505 | 486 | } |
575 | 556 | { |
576 | 557 | tag: "gt", |
577 | 558 | customRegisFunc: func(ut ut.Translator) (err error) { |
578 | ||
579 | 559 | if err = ut.Add("gt-string", "{0} must be greater than {1} in length", false); err != nil { |
580 | 560 | return |
581 | 561 | } |
611 | 591 | return |
612 | 592 | }, |
613 | 593 | customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { |
614 | ||
615 | 594 | var err error |
616 | 595 | var t string |
617 | 596 | var f64 float64 |
619 | 598 | var kind reflect.Kind |
620 | 599 | |
621 | 600 | fn := func() (err error) { |
622 | ||
623 | 601 | if idx := strings.Index(fe.Param(), "."); idx != -1 { |
624 | 602 | digits = uint64(len(fe.Param()[idx+1:])) |
625 | 603 | } |
695 | 673 | { |
696 | 674 | tag: "gte", |
697 | 675 | customRegisFunc: func(ut ut.Translator) (err error) { |
698 | ||
699 | 676 | if err = ut.Add("gte-string", "{0} must be at least {1} in length", false); err != nil { |
700 | 677 | return |
701 | 678 | } |
731 | 708 | return |
732 | 709 | }, |
733 | 710 | customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { |
734 | ||
735 | 711 | var err error |
736 | 712 | var t string |
737 | 713 | var f64 float64 |
739 | 715 | var kind reflect.Kind |
740 | 716 | |
741 | 717 | fn := func() (err error) { |
742 | ||
743 | 718 | if idx := strings.Index(fe.Param(), "."); idx != -1 { |
744 | 719 | digits = uint64(len(fe.Param()[idx+1:])) |
745 | 720 | } |
817 | 792 | translation: "{0} must be equal to {1}", |
818 | 793 | override: false, |
819 | 794 | customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { |
820 | ||
821 | 795 | t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) |
822 | 796 | if err != nil { |
823 | 797 | log.Printf("warning: error translating FieldError: %#v", fe) |
832 | 806 | translation: "{0} must be equal to {1}", |
833 | 807 | override: false, |
834 | 808 | customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { |
835 | ||
836 | 809 | t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) |
837 | 810 | if err != nil { |
838 | 811 | log.Printf("warning: error translating FieldError: %#v", fe) |
847 | 820 | translation: "{0} cannot be equal to {1}", |
848 | 821 | override: false, |
849 | 822 | customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { |
850 | ||
851 | 823 | t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) |
852 | 824 | if err != nil { |
853 | 825 | log.Printf("warning: error translating FieldError: %#v", fe) |
862 | 834 | translation: "{0} must be greater than {1}", |
863 | 835 | override: false, |
864 | 836 | customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { |
865 | ||
866 | 837 | t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) |
867 | 838 | if err != nil { |
868 | 839 | log.Printf("warning: error translating FieldError: %#v", fe) |
877 | 848 | translation: "{0} must be greater than or equal to {1}", |
878 | 849 | override: false, |
879 | 850 | customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { |
880 | ||
881 | 851 | t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) |
882 | 852 | if err != nil { |
883 | 853 | log.Printf("warning: error translating FieldError: %#v", fe) |
892 | 862 | translation: "{0} must be less than {1}", |
893 | 863 | override: false, |
894 | 864 | customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { |
895 | ||
896 | 865 | t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) |
897 | 866 | if err != nil { |
898 | 867 | log.Printf("warning: error translating FieldError: %#v", fe) |
907 | 876 | translation: "{0} must be less than or equal to {1}", |
908 | 877 | override: false, |
909 | 878 | customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { |
910 | ||
911 | 879 | t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) |
912 | 880 | if err != nil { |
913 | 881 | log.Printf("warning: error translating FieldError: %#v", fe) |
922 | 890 | translation: "{0} cannot be equal to {1}", |
923 | 891 | override: false, |
924 | 892 | customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { |
925 | ||
926 | 893 | t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) |
927 | 894 | if err != nil { |
928 | 895 | log.Printf("warning: error translating FieldError: %#v", fe) |
937 | 904 | translation: "{0} must be greater than {1}", |
938 | 905 | override: false, |
939 | 906 | customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { |
940 | ||
941 | 907 | t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) |
942 | 908 | if err != nil { |
943 | 909 | log.Printf("warning: error translating FieldError: %#v", fe) |
952 | 918 | translation: "{0} must be greater than or equal to {1}", |
953 | 919 | override: false, |
954 | 920 | customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { |
955 | ||
956 | 921 | t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) |
957 | 922 | if err != nil { |
958 | 923 | log.Printf("warning: error translating FieldError: %#v", fe) |
967 | 932 | translation: "{0} must be less than {1}", |
968 | 933 | override: false, |
969 | 934 | customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { |
970 | ||
971 | 935 | t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) |
972 | 936 | if err != nil { |
973 | 937 | log.Printf("warning: error translating FieldError: %#v", fe) |
982 | 946 | translation: "{0} must be less than or equal to {1}", |
983 | 947 | override: false, |
984 | 948 | customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { |
985 | ||
986 | 949 | t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) |
987 | 950 | if err != nil { |
988 | 951 | log.Printf("warning: error translating FieldError: %#v", fe) |
1072 | 1035 | translation: "{0} must contain the text '{1}'", |
1073 | 1036 | override: false, |
1074 | 1037 | customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { |
1075 | ||
1076 | 1038 | t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) |
1077 | 1039 | if err != nil { |
1078 | 1040 | log.Printf("warning: error translating FieldError: %#v", fe) |
1087 | 1049 | translation: "{0} must contain at least one of the following characters '{1}'", |
1088 | 1050 | override: false, |
1089 | 1051 | customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { |
1090 | ||
1091 | 1052 | t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) |
1092 | 1053 | if err != nil { |
1093 | 1054 | log.Printf("warning: error translating FieldError: %#v", fe) |
1102 | 1063 | translation: "{0} cannot contain the text '{1}'", |
1103 | 1064 | override: false, |
1104 | 1065 | customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { |
1105 | ||
1106 | 1066 | t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) |
1107 | 1067 | if err != nil { |
1108 | 1068 | log.Printf("warning: error translating FieldError: %#v", fe) |
1117 | 1077 | translation: "{0} cannot contain any of the following characters '{1}'", |
1118 | 1078 | override: false, |
1119 | 1079 | customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { |
1120 | ||
1121 | 1080 | t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) |
1122 | 1081 | if err != nil { |
1123 | 1082 | log.Printf("warning: error translating FieldError: %#v", fe) |
1132 | 1091 | translation: "{0} cannot contain the following '{1}'", |
1133 | 1092 | override: false, |
1134 | 1093 | customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { |
1135 | ||
1136 | 1094 | t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) |
1137 | 1095 | if err != nil { |
1138 | 1096 | log.Printf("warning: error translating FieldError: %#v", fe) |
1324 | 1282 | tag: "json", |
1325 | 1283 | translation: "{0} must be a valid json string", |
1326 | 1284 | override: false, |
1327 | }, | |
1328 | { | |
1285 | }, | |
1286 | { | |
1329 | 1287 | tag: "lowercase", |
1330 | 1288 | translation: "{0} must be a lowercase string", |
1331 | 1289 | override: false, |
1340 | 1298 | translation: "{0} does not match the {1} format", |
1341 | 1299 | override: false, |
1342 | 1300 | customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { |
1343 | ||
1301 | t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) | |
1302 | if err != nil { | |
1303 | log.Printf("warning: error translating FieldError: %#v", fe) | |
1304 | return fe.(error).Error() | |
1305 | } | |
1306 | ||
1307 | return t | |
1308 | }, | |
1309 | }, | |
1310 | { | |
1311 | tag: "postcode_iso3166_alpha2", | |
1312 | translation: "{0} does not match postcode format of {1} country", | |
1313 | override: false, | |
1314 | customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { | |
1315 | t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) | |
1316 | if err != nil { | |
1317 | log.Printf("warning: error translating FieldError: %#v", fe) | |
1318 | return fe.(error).Error() | |
1319 | } | |
1320 | ||
1321 | return t | |
1322 | }, | |
1323 | }, | |
1324 | { | |
1325 | tag: "postcode_iso3166_alpha2_field", | |
1326 | translation: "{0} does not match postcode format of country in {1} field", | |
1327 | override: false, | |
1328 | customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { | |
1344 | 1329 | t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) |
1345 | 1330 | if err != nil { |
1346 | 1331 | log.Printf("warning: error translating FieldError: %#v", fe) |
1355 | 1340 | for _, t := range translations { |
1356 | 1341 | |
1357 | 1342 | if t.customTransFunc != nil && t.customRegisFunc != nil { |
1358 | ||
1359 | 1343 | err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, t.customTransFunc) |
1360 | ||
1361 | 1344 | } else if t.customTransFunc != nil && t.customRegisFunc == nil { |
1362 | ||
1363 | 1345 | err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), t.customTransFunc) |
1364 | ||
1365 | 1346 | } else if t.customTransFunc == nil && t.customRegisFunc != nil { |
1366 | ||
1367 | 1347 | err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, translateFunc) |
1368 | ||
1369 | 1348 | } else { |
1370 | 1349 | err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), translateFunc) |
1371 | 1350 | } |
1379 | 1358 | } |
1380 | 1359 | |
1381 | 1360 | func registrationFunc(tag string, translation string, override bool) validator.RegisterTranslationsFunc { |
1382 | ||
1383 | 1361 | return func(ut ut.Translator) (err error) { |
1384 | ||
1385 | 1362 | if err = ut.Add(tag, translation, override); err != nil { |
1386 | 1363 | return |
1387 | 1364 | } |
1388 | 1365 | |
1389 | 1366 | return |
1390 | ||
1391 | 1367 | } |
1392 | ||
1393 | 1368 | } |
1394 | 1369 | |
1395 | 1370 | func translateFunc(ut ut.Translator, fe validator.FieldError) string { |
1396 | ||
1397 | 1371 | t, err := ut.T(fe.Tag(), fe.Field()) |
1398 | 1372 | if err != nil { |
1399 | 1373 | log.Printf("warning: error translating FieldError: %#v", fe) |
10 | 10 | ) |
11 | 11 | |
12 | 12 | func TestTranslations(t *testing.T) { |
13 | ||
14 | 13 | eng := english.New() |
15 | 14 | uni := ut.New(eng, eng) |
16 | 15 | trans, _ := uni.GetTranslator("en") |
144 | 143 | LowercaseString string `validate:"lowercase"` |
145 | 144 | UppercaseString string `validate:"uppercase"` |
146 | 145 | Datetime string `validate:"datetime=2006-01-02"` |
146 | PostCode string `validate:"postcode_iso3166_alpha2=SG"` | |
147 | PostCodeCountry string | |
148 | PostCodeByField string `validate:"postcode_iso3166_alpha2_field=PostCodeCountry"` | |
147 | 149 | } |
148 | 150 | |
149 | 151 | var test Test |
654 | 656 | { |
655 | 657 | ns: "Test.Datetime", |
656 | 658 | expected: "Datetime does not match the 2006-01-02 format", |
659 | }, | |
660 | { | |
661 | ns: "Test.PostCode", | |
662 | expected: "PostCode does not match postcode format of SG country", | |
663 | }, | |
664 | { | |
665 | ns: "Test.PostCodeByField", | |
666 | expected: "PostCodeByField does not match postcode format of country in PostCodeCountry field", | |
657 | 667 | }, |
658 | 668 | } |
659 | 669 | |
671 | 681 | NotEqual(t, fe, nil) |
672 | 682 | Equal(t, tt.expected, fe.Translate(trans)) |
673 | 683 | } |
674 | ||
675 | 684 | } |
73 | 73 | } |
74 | 74 | } |
75 | 75 | |
76 | v.traverseField(ctx, parent, current.Field(f.idx), ns, structNs, f, f.cTags) | |
76 | v.traverseField(ctx, current, current.Field(f.idx), ns, structNs, f, f.cTags) | |
77 | 77 | } |
78 | 78 | } |
79 | 79 | |
221 | 221 | structNs = append(append(structNs, cf.name...), '.') |
222 | 222 | } |
223 | 223 | |
224 | v.validateStruct(ctx, current, current, typ, ns, structNs, ct) | |
224 | v.validateStruct(ctx, parent, current, typ, ns, structNs, ct) | |
225 | 225 | return |
226 | 226 | } |
227 | 227 | } |
28 | 28 | requiredWithAllTag = "required_with_all" |
29 | 29 | requiredIfTag = "required_if" |
30 | 30 | requiredUnlessTag = "required_unless" |
31 | excludedWithoutAllTag = "excluded_without_all" | |
32 | excludedWithoutTag = "excluded_without" | |
33 | excludedWithTag = "excluded_with" | |
34 | excludedWithAllTag = "excluded_with_all" | |
31 | 35 | skipValidationTag = "-" |
32 | 36 | diveTag = "dive" |
33 | 37 | keysTag = "keys" |
110 | 114 | |
111 | 115 | switch k { |
112 | 116 | // these require that even if the value is nil that the validation should run, omitempty still overrides this behaviour |
113 | case requiredIfTag, requiredUnlessTag, requiredWithTag, requiredWithAllTag, requiredWithoutTag, requiredWithoutAllTag: | |
117 | case requiredIfTag, requiredUnlessTag, requiredWithTag, requiredWithAllTag, requiredWithoutTag, requiredWithoutAllTag, | |
118 | excludedWithTag, excludedWithAllTag, excludedWithoutTag, excludedWithoutAllTag: | |
114 | 119 | _ = v.registerValidation(k, wrapFunc(val), true, true) |
115 | 120 | default: |
116 | 121 | // no need to error check here, baked in will always be valid |
135 | 140 | // SetTagName allows for changing of the default tag name of 'validate' |
136 | 141 | func (v *Validate) SetTagName(name string) { |
137 | 142 | v.tagName = name |
143 | } | |
144 | ||
145 | // ValidateMapCtx validates a map using a map of validation rules and allows passing of contextual | |
146 | // validation validation information via context.Context. | |
147 | func (v Validate) ValidateMapCtx(ctx context.Context, data map[string]interface{}, rules map[string]interface{}) map[string]interface{} { | |
148 | errs := make(map[string]interface{}) | |
149 | for field, rule := range rules { | |
150 | if reflect.ValueOf(rule).Kind() == reflect.Map && reflect.ValueOf(data[field]).Kind() == reflect.Map { | |
151 | err := v.ValidateMapCtx(ctx, data[field].(map[string]interface{}), rule.(map[string]interface{})) | |
152 | if len(err) > 0 { | |
153 | errs[field] = err | |
154 | } | |
155 | } else if reflect.ValueOf(rule).Kind() == reflect.Map { | |
156 | errs[field] = errors.New("The field: '" + field + "' is not a map to dive") | |
157 | } else { | |
158 | err := v.VarCtx(ctx, data[field], rule.(string)) | |
159 | if err != nil { | |
160 | errs[field] = err | |
161 | } | |
162 | } | |
163 | } | |
164 | return errs | |
165 | } | |
166 | ||
167 | // ValidateMap validates map data form a map of tags | |
168 | func (v *Validate) ValidateMap(data map[string]interface{}, rules map[string]interface{}) map[string]interface{} { | |
169 | return v.ValidateMapCtx(context.Background(), data, rules) | |
138 | 170 | } |
139 | 171 | |
140 | 172 | // RegisterTagNameFunc registers a function to get alternate names for StructFields. |
408 | 440 | if len(flds) > 0 { |
409 | 441 | |
410 | 442 | vd.misc = append(vd.misc[0:0], name...) |
411 | vd.misc = append(vd.misc, '.') | |
443 | // Don't append empty name for unnamed structs | |
444 | if len(vd.misc) != 0 { | |
445 | vd.misc = append(vd.misc, '.') | |
446 | } | |
412 | 447 | |
413 | 448 | for _, s := range flds { |
414 | 449 |
13 | 13 | "testing" |
14 | 14 | "time" |
15 | 15 | |
16 | "github.com/go-playground/assert/v2" | |
16 | 17 | . "github.com/go-playground/assert/v2" |
17 | 18 | "github.com/go-playground/locales/en" |
18 | 19 | "github.com/go-playground/locales/fr" |
107 | 108 | } |
108 | 109 | |
109 | 110 | func AssertError(t *testing.T, err error, nsKey, structNsKey, field, structField, expectedTag string) { |
110 | ||
111 | 111 | errs := err.(ValidationErrors) |
112 | 112 | |
113 | 113 | found := false |
149 | 149 | } |
150 | 150 | |
151 | 151 | func getError(err error, nsKey, structNsKey string) FieldError { |
152 | ||
153 | 152 | errs := err.(ValidationErrors) |
154 | 153 | |
155 | 154 | var fe FieldError |
169 | 168 | } |
170 | 169 | |
171 | 170 | func (v valuer) Value() (driver.Value, error) { |
172 | ||
173 | 171 | if v.Name == "errorme" { |
174 | 172 | panic("SQL Driver Valuer error: some kind of error") |
175 | 173 | // return nil, errors.New("some kind of error") |
188 | 186 | } |
189 | 187 | |
190 | 188 | func ValidateCustomType(field reflect.Value) interface{} { |
191 | ||
192 | 189 | if cust, ok := field.Interface().(MadeUpCustomType); ok { |
193 | 190 | |
194 | 191 | if len(cust.FirstName) == 0 || len(cust.LastName) == 0 { |
202 | 199 | } |
203 | 200 | |
204 | 201 | func OverrideIntTypeForSomeReason(field reflect.Value) interface{} { |
205 | ||
206 | 202 | if i, ok := field.Interface().(int); ok { |
207 | 203 | if i == 1 { |
208 | 204 | return "1" |
222 | 218 | } |
223 | 219 | |
224 | 220 | func ValidateValuerType(field reflect.Value) interface{} { |
225 | ||
226 | 221 | if valuer, ok := field.Interface().(driver.Valuer); ok { |
227 | 222 | |
228 | 223 | val, err := valuer.Value() |
260 | 255 | } |
261 | 256 | |
262 | 257 | func StructValidationTestStructSuccess(sl StructLevel) { |
263 | ||
264 | 258 | st := sl.Current().Interface().(TestStruct) |
265 | 259 | |
266 | 260 | if st.String != "good value" { |
269 | 263 | } |
270 | 264 | |
271 | 265 | func StructValidationTestStruct(sl StructLevel) { |
272 | ||
273 | 266 | st := sl.Current().Interface().(TestStruct) |
274 | 267 | |
275 | 268 | if st.String != "bad value" { |
278 | 271 | } |
279 | 272 | |
280 | 273 | func StructValidationNoTestStructCustomName(sl StructLevel) { |
281 | ||
282 | 274 | st := sl.Current().Interface().(TestStruct) |
283 | 275 | |
284 | 276 | if st.String != "bad value" { |
287 | 279 | } |
288 | 280 | |
289 | 281 | func StructValidationTestStructInvalid(sl StructLevel) { |
290 | ||
291 | 282 | st := sl.Current().Interface().(TestStruct) |
292 | 283 | |
293 | 284 | if st.String != "bad value" { |
296 | 287 | } |
297 | 288 | |
298 | 289 | func StructValidationTestStructReturnValidationErrors(sl StructLevel) { |
299 | ||
300 | 290 | s := sl.Current().Interface().(TestStructReturnValidationErrors) |
301 | 291 | |
302 | 292 | errs := sl.Validator().Struct(s.Inner1.Inner2) |
308 | 298 | } |
309 | 299 | |
310 | 300 | func StructValidationTestStructReturnValidationErrors2(sl StructLevel) { |
311 | ||
312 | 301 | s := sl.Current().Interface().(TestStructReturnValidationErrors) |
313 | 302 | |
314 | 303 | errs := sl.Validator().Struct(s.Inner1.Inner2) |
336 | 325 | } |
337 | 326 | |
338 | 327 | func StructLevelInvalidError(sl StructLevel) { |
339 | ||
340 | 328 | top := sl.Top().Interface().(StructLevelInvalidErr) |
341 | 329 | s := sl.Current().Interface().(StructLevelInvalidErr) |
342 | 330 | |
358 | 346 | } |
359 | 347 | |
360 | 348 | func TestStructLevelInvalidError(t *testing.T) { |
361 | ||
362 | 349 | validate := New() |
363 | 350 | validate.RegisterStructValidation(StructLevelInvalidError, StructLevelInvalidErr{}) |
364 | 351 | |
382 | 369 | } |
383 | 370 | |
384 | 371 | func TestNameNamespace(t *testing.T) { |
385 | ||
386 | 372 | type Inner2Namespace struct { |
387 | 373 | String []string `validate:"dive,required" json:"JSONString"` |
388 | 374 | } |
431 | 417 | } |
432 | 418 | |
433 | 419 | func TestAnonymous(t *testing.T) { |
434 | ||
435 | 420 | validate := New() |
436 | 421 | validate.RegisterTagNameFunc(func(fld reflect.StructField) string { |
437 | 422 | name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] |
499 | 484 | } |
500 | 485 | |
501 | 486 | func TestAnonymousSameStructDifferentTags(t *testing.T) { |
502 | ||
503 | 487 | validate := New() |
504 | 488 | validate.RegisterTagNameFunc(func(fld reflect.StructField) string { |
505 | 489 | name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] |
544 | 528 | } |
545 | 529 | |
546 | 530 | func TestStructLevelReturnValidationErrors(t *testing.T) { |
547 | ||
548 | 531 | validate := New() |
549 | 532 | validate.RegisterStructValidation(StructValidationTestStructReturnValidationErrors, TestStructReturnValidationErrors{}) |
550 | 533 | |
574 | 557 | } |
575 | 558 | |
576 | 559 | func TestStructLevelReturnValidationErrorsWithJSON(t *testing.T) { |
577 | ||
578 | 560 | validate := New() |
579 | 561 | validate.RegisterTagNameFunc(func(fld reflect.StructField) string { |
580 | 562 | name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] |
631 | 613 | } |
632 | 614 | |
633 | 615 | func TestStructLevelValidations(t *testing.T) { |
634 | ||
635 | 616 | v1 := New() |
636 | 617 | v1.RegisterStructValidation(StructValidationTestStruct, TestStruct{}) |
637 | 618 | |
665 | 646 | } |
666 | 647 | |
667 | 648 | func TestAliasTags(t *testing.T) { |
668 | ||
669 | 649 | validate := New() |
670 | 650 | validate.RegisterAlias("iscoloralias", "hexcolor|rgb|rgba|hsl|hsla") |
671 | 651 | |
713 | 693 | } |
714 | 694 | |
715 | 695 | func TestNilValidator(t *testing.T) { |
716 | ||
717 | 696 | type TestStruct struct { |
718 | 697 | Test string `validate:"required"` |
719 | 698 | } |
723 | 702 | var val *Validate |
724 | 703 | |
725 | 704 | fn := func(fl FieldLevel) bool { |
726 | ||
727 | 705 | return fl.Parent().String() == fl.Field().String() |
728 | 706 | } |
729 | 707 | |
948 | 926 | NotEqual(t, errs, nil) |
949 | 927 | AssertError(t, errs, "TestPartial.Anonymous.SubAnonStruct[0].Test", "TestPartial.Anonymous.SubAnonStruct[0].Test", "Test", "Test", "required") |
950 | 928 | |
929 | // Test for unnamed struct | |
930 | testStruct := &TestStruct{ | |
931 | String: "test", | |
932 | } | |
933 | unnamedStruct := struct { | |
934 | String string `validate:"required" json:"StringVal"` | |
935 | }{String: "test"} | |
936 | composedUnnamedStruct := struct{ *TestStruct }{&TestStruct{String: "test"}} | |
937 | ||
938 | errs = validate.StructPartial(testStruct, "String") | |
939 | Equal(t, errs, nil) | |
940 | ||
941 | errs = validate.StructPartial(unnamedStruct, "String") | |
942 | Equal(t, errs, nil) | |
943 | ||
944 | errs = validate.StructPartial(composedUnnamedStruct, "TestStruct.String") | |
945 | Equal(t, errs, nil) | |
946 | ||
947 | testStruct.String = "" | |
948 | errs = validate.StructPartial(testStruct, "String") | |
949 | NotEqual(t, errs, nil) | |
950 | AssertError(t, errs, "TestStruct.String", "TestStruct.String", "String", "String", "required") | |
951 | ||
952 | unnamedStruct.String = "" | |
953 | errs = validate.StructPartial(unnamedStruct, "String") | |
954 | NotEqual(t, errs, nil) | |
955 | AssertError(t, errs, "String", "String", "String", "String", "required") | |
956 | ||
957 | composedUnnamedStruct.String = "" | |
958 | errs = validate.StructPartial(composedUnnamedStruct, "TestStruct.String") | |
959 | NotEqual(t, errs, nil) | |
960 | AssertError(t, errs, "TestStruct.String", "TestStruct.String", "String", "String", "required") | |
951 | 961 | } |
952 | 962 | |
953 | 963 | func TestCrossStructLteFieldValidation(t *testing.T) { |
1637 | 1647 | i := 1 |
1638 | 1648 | j = 1 |
1639 | 1649 | k = 1.543 |
1650 | b := true | |
1640 | 1651 | arr := []string{"test"} |
1641 | 1652 | |
1642 | 1653 | s2 := "abcd" |
1643 | 1654 | i2 := 1 |
1644 | 1655 | j2 = 1 |
1645 | 1656 | k2 = 1.543 |
1657 | b2 := true | |
1646 | 1658 | arr2 := []string{"test"} |
1647 | 1659 | arr3 := []string{"test", "test2"} |
1648 | 1660 | now2 := now |
1663 | 1675 | NotEqual(t, errs, nil) |
1664 | 1676 | AssertError(t, errs, "", "", "", "", "necsfield") |
1665 | 1677 | |
1678 | errs = validate.VarWithValue(b2, b, "necsfield") | |
1679 | NotEqual(t, errs, nil) | |
1680 | AssertError(t, errs, "", "", "", "", "necsfield") | |
1681 | ||
1666 | 1682 | errs = validate.VarWithValue(arr2, arr, "necsfield") |
1667 | 1683 | NotEqual(t, errs, nil) |
1668 | 1684 | AssertError(t, errs, "", "", "", "", "necsfield") |
1788 | 1804 | errs = validate.Struct(test) |
1789 | 1805 | Equal(t, errs, nil) |
1790 | 1806 | |
1791 | newTime := time.Now().UTC() | |
1807 | newTime := time.Now().Add(time.Hour).UTC() | |
1792 | 1808 | test.CreatedAt = &newTime |
1793 | 1809 | |
1794 | 1810 | errs = validate.Struct(test) |
1801 | 1817 | i := 1 |
1802 | 1818 | j = 1 |
1803 | 1819 | k = 1.543 |
1820 | b := true | |
1804 | 1821 | arr := []string{"test"} |
1805 | 1822 | |
1806 | 1823 | var j2 uint64 |
1809 | 1826 | i2 := 1 |
1810 | 1827 | j2 = 1 |
1811 | 1828 | k2 = 1.543 |
1829 | b2 := true | |
1812 | 1830 | arr2 := []string{"test"} |
1813 | 1831 | arr3 := []string{"test", "test2"} |
1814 | 1832 | now2 := now |
1825 | 1843 | errs = validate.VarWithValue(k2, k, "eqcsfield") |
1826 | 1844 | Equal(t, errs, nil) |
1827 | 1845 | |
1846 | errs = validate.VarWithValue(b2, b, "eqcsfield") | |
1847 | Equal(t, errs, nil) | |
1848 | ||
1828 | 1849 | errs = validate.VarWithValue(arr2, arr, "eqcsfield") |
1829 | 1850 | Equal(t, errs, nil) |
1830 | 1851 | |
1927 | 1948 | } |
1928 | 1949 | |
1929 | 1950 | func TestCrossNamespaceFieldValidation(t *testing.T) { |
1930 | ||
1931 | 1951 | type SliceStruct struct { |
1932 | 1952 | Name string |
1933 | 1953 | } |
2165 | 2185 | } |
2166 | 2186 | |
2167 | 2187 | func TestExistsValidation(t *testing.T) { |
2168 | ||
2169 | 2188 | jsonText := "{ \"truthiness2\": true }" |
2170 | 2189 | |
2171 | 2190 | type Thing struct { |
2196 | 2215 | } |
2197 | 2216 | |
2198 | 2217 | func TestSQLValue2Validation(t *testing.T) { |
2199 | ||
2200 | 2218 | validate := New() |
2201 | 2219 | validate.RegisterCustomTypeFunc(ValidateValuerType, valuer{}, (*driver.Valuer)(nil), sql.NullString{}, sql.NullInt64{}, sql.NullBool{}, sql.NullFloat64{}) |
2202 | 2220 | validate.RegisterCustomTypeFunc(ValidateCustomType, MadeUpCustomType{}) |
2247 | 2265 | } |
2248 | 2266 | |
2249 | 2267 | func TestSQLValueValidation(t *testing.T) { |
2250 | ||
2251 | 2268 | validate := New() |
2252 | 2269 | validate.RegisterCustomTypeFunc(ValidateValuerType, (*driver.Valuer)(nil), valuer{}) |
2253 | 2270 | validate.RegisterCustomTypeFunc(ValidateCustomType, MadeUpCustomType{}) |
2925 | 2942 | } |
2926 | 2943 | |
2927 | 2944 | func TestSliceMapArrayChanFuncPtrInterfaceRequiredValidation(t *testing.T) { |
2928 | ||
2929 | 2945 | validate := New() |
2930 | 2946 | |
2931 | 2947 | var m map[string]string |
3003 | 3019 | } |
3004 | 3020 | |
3005 | 3021 | func TestDatePtrValidationIssueValidation(t *testing.T) { |
3006 | ||
3007 | 3022 | type Test struct { |
3008 | 3023 | LastViewed *time.Time |
3009 | 3024 | Reminder *time.Time |
3055 | 3070 | } |
3056 | 3071 | |
3057 | 3072 | func TestInterfaceErrValidation(t *testing.T) { |
3058 | ||
3059 | 3073 | var v2 interface{} = 1 |
3060 | 3074 | var v1 interface{} = v2 |
3061 | 3075 | |
3229 | 3243 | } |
3230 | 3244 | |
3231 | 3245 | func TestMapDiveValidation(t *testing.T) { |
3232 | ||
3233 | 3246 | validate := New() |
3234 | 3247 | |
3235 | 3248 | n := map[int]interface{}{0: nil} |
3352 | 3365 | } |
3353 | 3366 | |
3354 | 3367 | func TestArrayDiveValidation(t *testing.T) { |
3355 | ||
3356 | 3368 | validate := New() |
3357 | 3369 | |
3358 | 3370 | arr := []string{"ok", "", "ok"} |
4361 | 4373 | } |
4362 | 4374 | |
4363 | 4375 | func TestExcludesRuneValidation(t *testing.T) { |
4364 | ||
4365 | 4376 | tests := []struct { |
4366 | 4377 | Value string `validate:"excludesrune=☻"` |
4367 | 4378 | Tag string |
4389 | 4400 | } |
4390 | 4401 | |
4391 | 4402 | func TestExcludesAllValidation(t *testing.T) { |
4392 | ||
4393 | 4403 | tests := []struct { |
4394 | 4404 | Value string `validate:"excludesall=@!{}[]"` |
4395 | 4405 | Tag string |
4435 | 4445 | } |
4436 | 4446 | |
4437 | 4447 | func TestExcludesValidation(t *testing.T) { |
4438 | ||
4439 | 4448 | tests := []struct { |
4440 | 4449 | Value string `validate:"excludes=@"` |
4441 | 4450 | Tag string |
4463 | 4472 | } |
4464 | 4473 | |
4465 | 4474 | func TestContainsRuneValidation(t *testing.T) { |
4466 | ||
4467 | 4475 | tests := []struct { |
4468 | 4476 | Value string `validate:"containsrune=☻"` |
4469 | 4477 | Tag string |
4491 | 4499 | } |
4492 | 4500 | |
4493 | 4501 | func TestContainsAnyValidation(t *testing.T) { |
4494 | ||
4495 | 4502 | tests := []struct { |
4496 | 4503 | Value string `validate:"containsany=@!{}[]"` |
4497 | 4504 | Tag string |
4519 | 4526 | } |
4520 | 4527 | |
4521 | 4528 | func TestContainsValidation(t *testing.T) { |
4522 | ||
4523 | 4529 | tests := []struct { |
4524 | 4530 | Value string `validate:"contains=@"` |
4525 | 4531 | Tag string |
4556 | 4562 | i := 1 |
4557 | 4563 | j = 1 |
4558 | 4564 | k = 1.543 |
4565 | b := true | |
4559 | 4566 | arr := []string{"test"} |
4560 | 4567 | now := time.Now().UTC() |
4561 | 4568 | |
4565 | 4572 | i2 := 3 |
4566 | 4573 | j2 = 2 |
4567 | 4574 | k2 = 1.5434456 |
4575 | b2 := false | |
4568 | 4576 | arr2 := []string{"test", "test2"} |
4569 | 4577 | arr3 := []string{"test"} |
4570 | 4578 | now2 := now |
4581 | 4589 | errs = validate.VarWithValue(k2, k, "nefield") |
4582 | 4590 | Equal(t, errs, nil) |
4583 | 4591 | |
4592 | errs = validate.VarWithValue(b2, b, "nefield") | |
4593 | Equal(t, errs, nil) | |
4594 | ||
4584 | 4595 | errs = validate.VarWithValue(arr2, arr, "nefield") |
4585 | 4596 | Equal(t, errs, nil) |
4586 | 4597 | |
4606 | 4617 | NotEqual(t, errs, nil) |
4607 | 4618 | AssertError(t, errs, "Test.Start", "Test.Start", "Start", "Start", "nefield") |
4608 | 4619 | |
4609 | now3 := time.Now().UTC() | |
4620 | now3 := time.Now().Add(time.Hour).UTC() | |
4610 | 4621 | |
4611 | 4622 | sv = &Test{ |
4612 | 4623 | Start: &now, |
4791 | 4802 | i := 1 |
4792 | 4803 | j = 1 |
4793 | 4804 | k = 1.543 |
4805 | b := true | |
4794 | 4806 | arr := []string{"test"} |
4795 | 4807 | now := time.Now().UTC() |
4796 | 4808 | |
4800 | 4812 | i2 := 1 |
4801 | 4813 | j2 = 1 |
4802 | 4814 | k2 = 1.543 |
4815 | b2 := true | |
4803 | 4816 | arr2 := []string{"test"} |
4804 | 4817 | arr3 := []string{"test", "test2"} |
4805 | 4818 | now2 := now |
4816 | 4829 | errs = validate.VarWithValue(k2, k, "eqfield") |
4817 | 4830 | Equal(t, errs, nil) |
4818 | 4831 | |
4832 | errs = validate.VarWithValue(b2, b, "eqfield") | |
4833 | Equal(t, errs, nil) | |
4834 | ||
4819 | 4835 | errs = validate.VarWithValue(arr2, arr, "eqfield") |
4820 | 4836 | Equal(t, errs, nil) |
4821 | 4837 | |
4839 | 4855 | errs = validate.Struct(sv) |
4840 | 4856 | Equal(t, errs, nil) |
4841 | 4857 | |
4842 | now3 := time.Now().UTC() | |
4858 | now3 := time.Now().Add(time.Hour).UTC() | |
4843 | 4859 | |
4844 | 4860 | sv = &Test{ |
4845 | 4861 | Start: &now, |
5095 | 5111 | } |
5096 | 5112 | |
5097 | 5113 | func TestBase64Validation(t *testing.T) { |
5098 | ||
5099 | 5114 | validate := New() |
5100 | 5115 | |
5101 | 5116 | s := "dW5pY29ybg==" |
5199 | 5214 | } |
5200 | 5215 | |
5201 | 5216 | func TestEthereumAddressValidation(t *testing.T) { |
5202 | ||
5203 | 5217 | validate := New() |
5204 | 5218 | |
5205 | 5219 | tests := []struct { |
5253 | 5267 | } |
5254 | 5268 | |
5255 | 5269 | func TestBitcoinAddressValidation(t *testing.T) { |
5256 | ||
5257 | 5270 | validate := New() |
5258 | 5271 | |
5259 | 5272 | tests := []struct { |
5363 | 5376 | } |
5364 | 5377 | |
5365 | 5378 | func TestBitcoinBech32AddressValidation(t *testing.T) { |
5366 | ||
5367 | 5379 | validate := New() |
5368 | 5380 | |
5369 | 5381 | tests := []struct { |
5414 | 5426 | } |
5415 | 5427 | |
5416 | 5428 | func TestNoStructLevelValidation(t *testing.T) { |
5417 | ||
5418 | 5429 | type Inner struct { |
5419 | 5430 | Test string `validate:"len=5"` |
5420 | 5431 | } |
5446 | 5457 | } |
5447 | 5458 | |
5448 | 5459 | func TestStructOnlyValidation(t *testing.T) { |
5449 | ||
5450 | 5460 | type Inner struct { |
5451 | 5461 | Test string `validate:"len=5"` |
5452 | 5462 | } |
6512 | 6522 | Equal(t, errs, nil) |
6513 | 6523 | |
6514 | 6524 | fn := func(fl FieldLevel) bool { |
6515 | ||
6516 | 6525 | return fl.Parent().String() == fl.Field().String() |
6517 | 6526 | } |
6518 | 6527 | |
6530 | 6539 | } |
6531 | 6540 | |
6532 | 6541 | func TestAddFunctions(t *testing.T) { |
6533 | ||
6534 | 6542 | fn := func(fl FieldLevel) bool { |
6535 | ||
6536 | 6543 | return true |
6537 | 6544 | } |
6538 | 6545 | |
6561 | 6568 | } |
6562 | 6569 | |
6563 | 6570 | func TestChangeTag(t *testing.T) { |
6564 | ||
6565 | 6571 | validate := New() |
6566 | 6572 | validate.SetTagName("val") |
6567 | 6573 | |
7208 | 7214 | } |
7209 | 7215 | |
7210 | 7216 | func TestUrnRFC2141(t *testing.T) { |
7211 | ||
7212 | var tests = []struct { | |
7217 | tests := []struct { | |
7213 | 7218 | param string |
7214 | 7219 | expected bool |
7215 | 7220 | }{ |
7285 | 7290 | } |
7286 | 7291 | |
7287 | 7292 | func TestUrl(t *testing.T) { |
7288 | ||
7289 | var tests = []struct { | |
7293 | tests := []struct { | |
7290 | 7294 | param string |
7291 | 7295 | expected bool |
7292 | 7296 | }{ |
7353 | 7357 | } |
7354 | 7358 | |
7355 | 7359 | func TestUri(t *testing.T) { |
7356 | ||
7357 | var tests = []struct { | |
7360 | tests := []struct { | |
7358 | 7361 | param string |
7359 | 7362 | expected bool |
7360 | 7363 | }{ |
7420 | 7423 | } |
7421 | 7424 | |
7422 | 7425 | func TestOrTag(t *testing.T) { |
7423 | ||
7424 | 7426 | validate := New() |
7425 | 7427 | |
7426 | 7428 | s := "rgba(0,31,255,0.5)" |
7450 | 7452 | Equal(t, errs, nil) |
7451 | 7453 | |
7452 | 7454 | s = "green" |
7453 | errs = validate.Var(s, "eq=|eq=blue,rgb|rgba") //should fail on first validation block | |
7455 | errs = validate.Var(s, "eq=|eq=blue,rgb|rgba") // should fail on first validation block | |
7454 | 7456 | NotEqual(t, errs, nil) |
7455 | 7457 | ve := errs.(ValidationErrors) |
7456 | 7458 | Equal(t, len(ve), 1) |
7463 | 7465 | |
7464 | 7466 | v2 := New() |
7465 | 7467 | v2.RegisterTagNameFunc(func(fld reflect.StructField) string { |
7466 | ||
7467 | 7468 | name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] |
7468 | 7469 | |
7469 | 7470 | if name == "-" { |
7488 | 7489 | } |
7489 | 7490 | |
7490 | 7491 | func TestHsla(t *testing.T) { |
7491 | ||
7492 | 7492 | validate := New() |
7493 | 7493 | |
7494 | 7494 | s := "hsla(360,100%,100%,1)" |
7535 | 7535 | } |
7536 | 7536 | |
7537 | 7537 | func TestHsl(t *testing.T) { |
7538 | ||
7539 | 7538 | validate := New() |
7540 | 7539 | |
7541 | 7540 | s := "hsl(360,100%,50%)" |
7573 | 7572 | } |
7574 | 7573 | |
7575 | 7574 | func TestRgba(t *testing.T) { |
7576 | ||
7577 | 7575 | validate := New() |
7578 | 7576 | |
7579 | 7577 | s := "rgba(0,31,255,0.5)" |
7619 | 7617 | } |
7620 | 7618 | |
7621 | 7619 | func TestRgb(t *testing.T) { |
7622 | ||
7623 | 7620 | validate := New() |
7624 | 7621 | |
7625 | 7622 | s := "rgb(0,31,255)" |
7661 | 7658 | } |
7662 | 7659 | |
7663 | 7660 | func TestEmail(t *testing.T) { |
7664 | ||
7665 | 7661 | validate := New() |
7666 | 7662 | |
7667 | 7663 | s := "test@mail.com" |
7729 | 7725 | } |
7730 | 7726 | |
7731 | 7727 | func TestHexColor(t *testing.T) { |
7732 | ||
7733 | 7728 | validate := New() |
7734 | 7729 | |
7735 | 7730 | s := "#fff" |
7757 | 7752 | } |
7758 | 7753 | |
7759 | 7754 | func TestHexadecimal(t *testing.T) { |
7760 | ||
7761 | 7755 | validate := New() |
7762 | 7756 | |
7763 | 7757 | s := "ff0044" |
7784 | 7778 | } |
7785 | 7779 | |
7786 | 7780 | func TestNumber(t *testing.T) { |
7787 | ||
7788 | 7781 | validate := New() |
7789 | 7782 | |
7790 | 7783 | s := "1" |
7832 | 7825 | } |
7833 | 7826 | |
7834 | 7827 | func TestNumeric(t *testing.T) { |
7835 | ||
7836 | 7828 | validate := New() |
7837 | 7829 | |
7838 | 7830 | s := "1" |
7875 | 7867 | } |
7876 | 7868 | |
7877 | 7869 | func TestAlphaNumeric(t *testing.T) { |
7878 | ||
7879 | 7870 | validate := New() |
7880 | 7871 | |
7881 | 7872 | s := "abcd123" |
7893 | 7884 | } |
7894 | 7885 | |
7895 | 7886 | func TestAlpha(t *testing.T) { |
7896 | ||
7897 | 7887 | validate := New() |
7898 | 7888 | |
7899 | 7889 | s := "abcd" |
7923 | 7913 | errs = validate.Var(1, "alpha") |
7924 | 7914 | NotEqual(t, errs, nil) |
7925 | 7915 | AssertError(t, errs, "", "", "", "", "alpha") |
7926 | ||
7927 | 7916 | } |
7928 | 7917 | |
7929 | 7918 | func TestStructStringValidation(t *testing.T) { |
7930 | ||
7931 | 7919 | validate := New() |
7932 | 7920 | |
7933 | 7921 | tSuccess := &TestString{ |
8009 | 7997 | } |
8010 | 7998 | |
8011 | 7999 | func TestStructInt32Validation(t *testing.T) { |
8012 | ||
8013 | 8000 | type TestInt32 struct { |
8014 | 8001 | Required int `validate:"required"` |
8015 | 8002 | Len int `validate:"len=10"` |
8073 | 8060 | } |
8074 | 8061 | |
8075 | 8062 | func TestStructUint64Validation(t *testing.T) { |
8076 | ||
8077 | 8063 | validate := New() |
8078 | 8064 | |
8079 | 8065 | tSuccess := &TestUint64{ |
8113 | 8099 | } |
8114 | 8100 | |
8115 | 8101 | func TestStructFloat64Validation(t *testing.T) { |
8116 | ||
8117 | 8102 | validate := New() |
8118 | 8103 | |
8119 | 8104 | tSuccess := &TestFloat64{ |
8153 | 8138 | } |
8154 | 8139 | |
8155 | 8140 | func TestStructSliceValidation(t *testing.T) { |
8156 | ||
8157 | 8141 | validate := New() |
8158 | 8142 | |
8159 | 8143 | tSuccess := &TestSlice{ |
8203 | 8187 | |
8204 | 8188 | _, ok := fe.Value().([]int) |
8205 | 8189 | Equal(t, ok, true) |
8206 | ||
8207 | 8190 | } |
8208 | 8191 | |
8209 | 8192 | func TestInvalidStruct(t *testing.T) { |
8210 | ||
8211 | 8193 | validate := New() |
8212 | 8194 | |
8213 | 8195 | s := &SubTest{ |
8232 | 8214 | } |
8233 | 8215 | |
8234 | 8216 | func TestInvalidValidatorFunction(t *testing.T) { |
8235 | ||
8236 | 8217 | validate := New() |
8237 | 8218 | |
8238 | 8219 | s := &SubTest{ |
8243 | 8224 | } |
8244 | 8225 | |
8245 | 8226 | func TestCustomFieldName(t *testing.T) { |
8246 | ||
8247 | 8227 | validate := New() |
8248 | 8228 | validate.RegisterTagNameFunc(func(fld reflect.StructField) string { |
8249 | 8229 | name := strings.SplitN(fld.Tag.Get("schema"), ",", 2)[0] |
8287 | 8267 | } |
8288 | 8268 | |
8289 | 8269 | func TestMutipleRecursiveExtractStructCache(t *testing.T) { |
8290 | ||
8291 | 8270 | validate := New() |
8292 | 8271 | |
8293 | 8272 | type Recursive struct { |
8304 | 8283 | ptr := fmt.Sprintf("%p", sc) |
8305 | 8284 | |
8306 | 8285 | for i := 0; i < 100; i++ { |
8307 | ||
8308 | 8286 | go func() { |
8309 | 8287 | <-proceed |
8310 | 8288 | sc := validate.extractStructCache(current, name) |
8317 | 8295 | |
8318 | 8296 | // Thanks @robbrockbank, see https://github.com/go-playground/validator/issues/249 |
8319 | 8297 | func TestPointerAndOmitEmpty(t *testing.T) { |
8320 | ||
8321 | 8298 | validate := New() |
8322 | 8299 | |
8323 | 8300 | type Test struct { |
8363 | 8340 | } |
8364 | 8341 | |
8365 | 8342 | func TestRequired(t *testing.T) { |
8366 | ||
8367 | 8343 | validate := New() |
8368 | 8344 | validate.RegisterTagNameFunc(func(fld reflect.StructField) string { |
8369 | 8345 | name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] |
8387 | 8363 | } |
8388 | 8364 | |
8389 | 8365 | func TestBoolEqual(t *testing.T) { |
8390 | ||
8391 | 8366 | validate := New() |
8392 | 8367 | |
8393 | 8368 | type Test struct { |
8415 | 8390 | validate := New() |
8416 | 8391 | err := validate.RegisterTranslation("required", trans, |
8417 | 8392 | func(ut ut.Translator) (err error) { |
8418 | ||
8419 | 8393 | // using this stype because multiple translation may have to be added for the full translation |
8420 | 8394 | if err = ut.Add("required", "{0} is a required field", false); err != nil { |
8421 | 8395 | return |
8422 | 8396 | } |
8423 | 8397 | |
8424 | 8398 | return |
8425 | ||
8426 | 8399 | }, func(ut ut.Translator, fe FieldError) string { |
8427 | ||
8428 | 8400 | t, err := ut.T(fe.Tag(), fe.Field()) |
8429 | 8401 | if err != nil { |
8430 | 8402 | fmt.Printf("warning: error translating FieldError: %#v", fe.(*fieldError)) |
8437 | 8409 | |
8438 | 8410 | err = validate.RegisterTranslation("required", fr, |
8439 | 8411 | func(ut ut.Translator) (err error) { |
8440 | ||
8441 | 8412 | // using this stype because multiple translation may have to be added for the full translation |
8442 | 8413 | if err = ut.Add("required", "{0} est un champ obligatoire", false); err != nil { |
8443 | 8414 | return |
8444 | 8415 | } |
8445 | 8416 | |
8446 | 8417 | return |
8447 | ||
8448 | 8418 | }, func(ut ut.Translator, fe FieldError) string { |
8449 | ||
8450 | 8419 | t, transErr := ut.T(fe.Tag(), fe.Field()) |
8451 | 8420 | if transErr != nil { |
8452 | 8421 | fmt.Printf("warning: error translating FieldError: %#v", fe.(*fieldError)) |
8524 | 8493 | validate := New() |
8525 | 8494 | err = validate.RegisterTranslation("required", trans, |
8526 | 8495 | func(ut ut.Translator) (err error) { |
8527 | ||
8528 | 8496 | // using this stype because multiple translation may have to be added for the full translation |
8529 | 8497 | if err = ut.Add("required", "{0} is a required field", false); err != nil { |
8530 | 8498 | return |
8531 | 8499 | } |
8532 | 8500 | |
8533 | 8501 | return |
8534 | ||
8535 | 8502 | }, func(ut ut.Translator, fe FieldError) string { |
8536 | ||
8537 | 8503 | t, err := ut.T(fe.Tag(), fe.Field()) |
8538 | 8504 | if err != nil { |
8539 | 8505 | fmt.Printf("warning: error translating FieldError: %#v", fe.(*fieldError)) |
8548 | 8514 | } |
8549 | 8515 | |
8550 | 8516 | func TestStructFiltered(t *testing.T) { |
8551 | ||
8552 | 8517 | p1 := func(ns []byte) bool { |
8553 | 8518 | if bytes.HasSuffix(ns, []byte("NoTag")) || bytes.HasSuffix(ns, []byte("Required")) { |
8554 | 8519 | return false |
8714 | 8679 | } |
8715 | 8680 | |
8716 | 8681 | func TestRequiredPtr(t *testing.T) { |
8717 | ||
8718 | 8682 | type Test struct { |
8719 | 8683 | Bool *bool `validate:"required"` |
8720 | 8684 | } |
8848 | 8812 | } |
8849 | 8813 | |
8850 | 8814 | func TestAlphanumericUnicodeValidation(t *testing.T) { |
8851 | ||
8852 | 8815 | tests := []struct { |
8853 | 8816 | param string |
8854 | 8817 | expected bool |
8891 | 8854 | } |
8892 | 8855 | |
8893 | 8856 | func TestArrayStructNamespace(t *testing.T) { |
8894 | ||
8895 | 8857 | validate := New() |
8896 | 8858 | validate.RegisterTagNameFunc(func(fld reflect.StructField) string { |
8897 | 8859 | name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] |
8920 | 8882 | } |
8921 | 8883 | |
8922 | 8884 | func TestMapStructNamespace(t *testing.T) { |
8923 | ||
8924 | 8885 | validate := New() |
8925 | 8886 | validate.RegisterTagNameFunc(func(fld reflect.StructField) string { |
8926 | 8887 | name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] |
9575 | 9536 | {"a%b", false}, |
9576 | 9537 | {"1%2", false}, |
9577 | 9538 | {"%%a%%", false}, |
9539 | {"hello", true}, | |
9540 | {"", true}, | |
9541 | {"+", true}, | |
9578 | 9542 | } |
9579 | 9543 | |
9580 | 9544 | validate := New() |
9601 | 9565 | } |
9602 | 9566 | |
9603 | 9567 | func TestKeys(t *testing.T) { |
9604 | ||
9605 | 9568 | type Test struct { |
9606 | 9569 | Test1 map[string]string `validate:"gt=0,dive,keys,eq=testkey,endkeys,eq=testval" json:"test1"` |
9607 | 9570 | Test2 map[int]int `validate:"gt=0,dive,keys,eq=3,endkeys,eq=4" json:"test2"` |
9770 | 9733 | } |
9771 | 9734 | |
9772 | 9735 | func TestKeyOrs(t *testing.T) { |
9773 | ||
9774 | 9736 | type Test struct { |
9775 | 9737 | Test1 map[string]string `validate:"gt=0,dive,keys,eq=testkey|eq=testkeyok,endkeys,eq=testval" json:"test1"` |
9776 | 9738 | } |
10027 | 9989 | Field6 uint `validate:"required_unless=Field5 2" json:"field_6"` |
10028 | 9990 | Field7 float32 `validate:"required_unless=Field6 0" json:"field_7"` |
10029 | 9991 | Field8 float64 `validate:"required_unless=Field7 0.0" json:"field_8"` |
9992 | Field9 bool `validate:"omitempty" json:"field_9"` | |
9993 | Field10 string `validate:"required_unless=Field9 true" json:"field_10"` | |
10030 | 9994 | }{ |
10031 | 9995 | FieldE: "test", |
10032 | 9996 | Field2: &fieldVal, |
10033 | 9997 | Field3: map[string]string{"key": "val"}, |
10034 | 9998 | Field4: "test", |
10035 | 9999 | Field5: 2, |
10000 | Field9: true, | |
10036 | 10001 | } |
10037 | 10002 | |
10038 | 10003 | validate := New() |
10052 | 10017 | Field5 string `validate:"required_unless=Field3 0" json:"field_5"` |
10053 | 10018 | Field6 string `validate:"required_unless=Inner.Field test" json:"field_6"` |
10054 | 10019 | Field7 string `validate:"required_unless=Inner2.Field test" json:"field_7"` |
10020 | Field8 bool `validate:"omitempty" json:"field_8"` | |
10021 | Field9 string `validate:"required_unless=Field8 true" json:"field_9"` | |
10055 | 10022 | }{ |
10056 | 10023 | Inner: &Inner{Field: &fieldVal}, |
10057 | 10024 | FieldE: "test", |
10062 | 10029 | NotEqual(t, errs, nil) |
10063 | 10030 | |
10064 | 10031 | ve := errs.(ValidationErrors) |
10065 | Equal(t, len(ve), 3) | |
10032 | Equal(t, len(ve), 4) | |
10066 | 10033 | AssertError(t, errs, "Field3", "Field3", "Field3", "Field3", "required_unless") |
10067 | 10034 | AssertError(t, errs, "Field4", "Field4", "Field4", "Field4", "required_unless") |
10068 | 10035 | AssertError(t, errs, "Field7", "Field7", "Field7", "Field7", "required_unless") |
10036 | AssertError(t, errs, "Field9", "Field9", "Field9", "Field9", "required_unless") | |
10069 | 10037 | |
10070 | 10038 | defer func() { |
10071 | 10039 | if r := recover(); r == nil { |
10201 | 10169 | name := fmt.Sprintf("Field%d", i) |
10202 | 10170 | AssertError(t, errs, name, name, name, name, "excluded_with") |
10203 | 10171 | } |
10172 | ||
10173 | test3 := struct { | |
10174 | Inner *Inner | |
10175 | Inner2 *Inner | |
10176 | Field string `validate:"omitempty" json:"field"` | |
10177 | FieldE string `validate:"omitempty" json:"field_e"` | |
10178 | Field1 string `validate:"excluded_with=FieldE" json:"field_1"` | |
10179 | Field2 *string `validate:"excluded_with=FieldE" json:"field_2"` | |
10180 | Field3 map[string]string `validate:"excluded_with=FieldE" json:"field_3"` | |
10181 | Field4 interface{} `validate:"excluded_with=FieldE" json:"field_4"` | |
10182 | Field5 string `validate:"excluded_with=Inner.FieldE" json:"field_5"` | |
10183 | Field6 string `validate:"excluded_with=Inner2.FieldE" json:"field_6"` | |
10184 | }{ | |
10185 | Inner: &Inner{FieldE: "populated"}, | |
10186 | Inner2: &Inner{FieldE: "populated"}, | |
10187 | FieldE: "populated", | |
10188 | } | |
10189 | ||
10190 | validate = New() | |
10191 | ||
10192 | errs = validate.Struct(test3) | |
10193 | Equal(t, errs, nil) | |
10204 | 10194 | } |
10205 | 10195 | |
10206 | 10196 | func TestExcludedWithout(t *testing.T) { |
10265 | 10255 | name := fmt.Sprintf("Field%d", i) |
10266 | 10256 | AssertError(t, errs, name, name, name, name, "excluded_without") |
10267 | 10257 | } |
10258 | ||
10259 | test3 := struct { | |
10260 | Inner *Inner | |
10261 | Inner2 *Inner | |
10262 | Field string `validate:"omitempty" json:"field"` | |
10263 | FieldE string `validate:"omitempty" json:"field_e"` | |
10264 | Field1 string `validate:"excluded_without=Field" json:"field_1"` | |
10265 | Field2 *string `validate:"excluded_without=Field" json:"field_2"` | |
10266 | Field3 map[string]string `validate:"excluded_without=Field" json:"field_3"` | |
10267 | Field4 interface{} `validate:"excluded_without=Field" json:"field_4"` | |
10268 | Field5 string `validate:"excluded_without=Inner.Field" json:"field_5"` | |
10269 | }{ | |
10270 | Inner: &Inner{Field: &fieldVal}, | |
10271 | Field: "populated", | |
10272 | } | |
10273 | ||
10274 | validate = New() | |
10275 | ||
10276 | errs = validate.Struct(test3) | |
10277 | Equal(t, errs, nil) | |
10268 | 10278 | } |
10269 | 10279 | |
10270 | 10280 | func TestExcludedWithAll(t *testing.T) { |
10333 | 10343 | name := fmt.Sprintf("Field%d", i) |
10334 | 10344 | AssertError(t, errs, name, name, name, name, "excluded_with_all") |
10335 | 10345 | } |
10346 | ||
10347 | test3 := struct { | |
10348 | Inner *Inner | |
10349 | Inner2 *Inner | |
10350 | Field string `validate:"omitempty" json:"field"` | |
10351 | FieldE string `validate:"omitempty" json:"field_e"` | |
10352 | Field1 string `validate:"excluded_with_all=FieldE Field" json:"field_1"` | |
10353 | Field2 *string `validate:"excluded_with_all=FieldE Field" json:"field_2"` | |
10354 | Field3 map[string]string `validate:"excluded_with_all=FieldE Field" json:"field_3"` | |
10355 | Field4 interface{} `validate:"excluded_with_all=FieldE Field" json:"field_4"` | |
10356 | Field5 string `validate:"excluded_with_all=Inner.FieldE" json:"field_5"` | |
10357 | Field6 string `validate:"excluded_with_all=Inner2.FieldE" json:"field_6"` | |
10358 | }{ | |
10359 | Inner: &Inner{FieldE: "populated"}, | |
10360 | Inner2: &Inner{FieldE: "populated"}, | |
10361 | Field: "populated", | |
10362 | FieldE: "populated", | |
10363 | } | |
10364 | ||
10365 | validate = New() | |
10366 | ||
10367 | errs = validate.Struct(test3) | |
10368 | Equal(t, errs, nil) | |
10336 | 10369 | } |
10337 | 10370 | |
10338 | 10371 | func TestExcludedWithoutAll(t *testing.T) { |
10351 | 10384 | Field2 *string `validate:"excluded_without_all=Field FieldE" json:"field_2"` |
10352 | 10385 | Field3 map[string]string `validate:"excluded_without_all=Field FieldE" json:"field_3"` |
10353 | 10386 | Field4 interface{} `validate:"excluded_without_all=Field FieldE" json:"field_4"` |
10354 | Field5 string `validate:"excluded_without_all=Inner.Field Inner.Field2" json:"field_5"` | |
10387 | Field5 string `validate:"excluded_without_all=Inner.Field Inner2.Field" json:"field_5"` | |
10355 | 10388 | }{ |
10356 | 10389 | Inner: &Inner{Field: &fieldVal}, |
10390 | Inner2: &Inner{Field: &fieldVal}, | |
10357 | 10391 | Field: "populated", |
10358 | 10392 | Field1: fieldVal, |
10359 | 10393 | Field2: &fieldVal, |
10397 | 10431 | name := fmt.Sprintf("Field%d", i) |
10398 | 10432 | AssertError(t, errs, name, name, name, name, "excluded_without_all") |
10399 | 10433 | } |
10434 | ||
10435 | test3 := struct { | |
10436 | Inner *Inner | |
10437 | Inner2 *Inner | |
10438 | Field string `validate:"omitempty" json:"field"` | |
10439 | FieldE string `validate:"omitempty" json:"field_e"` | |
10440 | Field1 string `validate:"excluded_without_all=Field FieldE" json:"field_1"` | |
10441 | Field2 *string `validate:"excluded_without_all=Field FieldE" json:"field_2"` | |
10442 | Field3 map[string]string `validate:"excluded_without_all=Field FieldE" json:"field_3"` | |
10443 | Field4 interface{} `validate:"excluded_without_all=Field FieldE" json:"field_4"` | |
10444 | Field5 string `validate:"excluded_without_all=Inner.Field Inner2.Field" json:"field_5"` | |
10445 | }{ | |
10446 | Inner: &Inner{Field: &fieldVal}, | |
10447 | Inner2: &Inner{Field: &fieldVal}, | |
10448 | Field: "populated", | |
10449 | FieldE: "populated", | |
10450 | } | |
10451 | ||
10452 | validate = New() | |
10453 | ||
10454 | errs = validate.Struct(test3) | |
10455 | Equal(t, errs, nil) | |
10400 | 10456 | } |
10401 | 10457 | |
10402 | 10458 | func TestRequiredWithAll(t *testing.T) { |
10454 | 10510 | } |
10455 | 10511 | |
10456 | 10512 | func TestRequiredWithout(t *testing.T) { |
10457 | ||
10458 | 10513 | type Inner struct { |
10459 | 10514 | Field *string |
10460 | 10515 | } |
10520 | 10575 | } |
10521 | 10576 | |
10522 | 10577 | func TestRequiredWithoutAll(t *testing.T) { |
10523 | ||
10524 | 10578 | fieldVal := "test" |
10525 | 10579 | test := struct { |
10526 | 10580 | Field1 string `validate:"omitempty" json:"field_1"` |
10577 | 10631 | } |
10578 | 10632 | |
10579 | 10633 | func TestAbilityToValidateNils(t *testing.T) { |
10580 | ||
10581 | 10634 | type TestStruct struct { |
10582 | 10635 | Test *string `validate:"nil"` |
10583 | 10636 | } |
10719 | 10772 | } |
10720 | 10773 | |
10721 | 10774 | func Test_hostnameport_validator(t *testing.T) { |
10722 | ||
10723 | 10775 | type Host struct { |
10724 | 10776 | Addr string `validate:"hostname_port"` |
10725 | 10777 | } |
10821 | 10873 | PanicMatches(t, func() { |
10822 | 10874 | _ = validate.Var(2, "uppercase") |
10823 | 10875 | }, "Bad field type int") |
10824 | ||
10825 | 10876 | } |
10826 | 10877 | |
10827 | 10878 | func TestDatetimeValidation(t *testing.T) { |
11032 | 11083 | }) |
11033 | 11084 | } |
11034 | 11085 | } |
11086 | ||
11087 | func TestBCP47LanguageTagValidation(t *testing.T) { | |
11088 | tests := []struct { | |
11089 | value string `validate:"bcp47_language_tag"` | |
11090 | tag string | |
11091 | expected bool | |
11092 | }{ | |
11093 | {"en-US", "bcp47_language_tag", true}, | |
11094 | {"en_GB", "bcp47_language_tag", true}, | |
11095 | {"es", "bcp47_language_tag", true}, | |
11096 | {"English", "bcp47_language_tag", false}, | |
11097 | {"ESES", "bcp47_language_tag", false}, | |
11098 | {"az-Cyrl-AZ", "bcp47_language_tag", true}, | |
11099 | {"en-029", "bcp47_language_tag", true}, | |
11100 | {"xog", "bcp47_language_tag", true}, | |
11101 | } | |
11102 | ||
11103 | validate := New() | |
11104 | ||
11105 | for i, test := range tests { | |
11106 | ||
11107 | errs := validate.Var(test.value, test.tag) | |
11108 | ||
11109 | if test.expected { | |
11110 | if !IsEqual(errs, nil) { | |
11111 | t.Fatalf("Index: %d locale failed Error: %s", i, errs) | |
11112 | } | |
11113 | } else { | |
11114 | if IsEqual(errs, nil) { | |
11115 | t.Fatalf("Index: %d locale failed Error: %s", i, errs) | |
11116 | } else { | |
11117 | val := getError(errs, "", "") | |
11118 | if val.Tag() != "bcp47_language_tag" { | |
11119 | t.Fatalf("Index: %d locale failed Error: %s", i, errs) | |
11120 | } | |
11121 | } | |
11122 | } | |
11123 | } | |
11124 | ||
11125 | PanicMatches(t, func() { | |
11126 | _ = validate.Var(2, "bcp47_language_tag") | |
11127 | }, "Bad field type int") | |
11128 | } | |
11129 | ||
11130 | func TestBicIsoFormatValidation(t *testing.T) { | |
11131 | tests := []struct { | |
11132 | value string `validate:"bic"` | |
11133 | tag string | |
11134 | expected bool | |
11135 | }{ | |
11136 | {"SBICKEN1345", "bic", true}, | |
11137 | {"SBICKEN1", "bic", true}, | |
11138 | {"SBICKENY", "bic", true}, | |
11139 | {"SBICKEN1YYP", "bic", true}, | |
11140 | {"SBIC23NXXX", "bic", false}, | |
11141 | {"S23CKENXXXX", "bic", false}, | |
11142 | {"SBICKENXX", "bic", false}, | |
11143 | {"SBICKENXX9", "bic", false}, | |
11144 | {"SBICKEN13458", "bic", false}, | |
11145 | {"SBICKEN", "bic", false}, | |
11146 | } | |
11147 | ||
11148 | validate := New() | |
11149 | ||
11150 | for i, test := range tests { | |
11151 | ||
11152 | errs := validate.Var(test.value, test.tag) | |
11153 | ||
11154 | if test.expected { | |
11155 | if !IsEqual(errs, nil) { | |
11156 | t.Fatalf("Index: %d bic failed Error: %s", i, errs) | |
11157 | } | |
11158 | } else { | |
11159 | if IsEqual(errs, nil) { | |
11160 | t.Fatalf("Index: %d bic failed Error: %s", i, errs) | |
11161 | } else { | |
11162 | val := getError(errs, "", "") | |
11163 | if val.Tag() != "bic" { | |
11164 | t.Fatalf("Index: %d bic failed Error: %s", i, errs) | |
11165 | } | |
11166 | } | |
11167 | } | |
11168 | } | |
11169 | } | |
11170 | ||
11171 | func TestPostCodeByIso3166Alpha2(t *testing.T) { | |
11172 | tests := map[string][]struct { | |
11173 | value string | |
11174 | expected bool | |
11175 | }{ | |
11176 | "VN": { | |
11177 | {"ABC", false}, | |
11178 | {"700000", true}, | |
11179 | {"A1", false}, | |
11180 | }, | |
11181 | "GB": { | |
11182 | {"EC1A 1BB", true}, | |
11183 | {"CF10 1B1H", false}, | |
11184 | }, | |
11185 | "VI": { | |
11186 | {"00803", true}, | |
11187 | {"1234567", false}, | |
11188 | }, | |
11189 | "LC": { // not support regexp for post code | |
11190 | {"123456", false}, | |
11191 | }, | |
11192 | "XX": { // not support country | |
11193 | {"123456", false}, | |
11194 | }, | |
11195 | } | |
11196 | ||
11197 | validate := New() | |
11198 | ||
11199 | for cc, ccTests := range tests { | |
11200 | for i, test := range ccTests { | |
11201 | errs := validate.Var(test.value, fmt.Sprintf("postcode_iso3166_alpha2=%s", cc)) | |
11202 | ||
11203 | if test.expected { | |
11204 | if !IsEqual(errs, nil) { | |
11205 | t.Fatalf("Index: %d postcode_iso3166_alpha2=%s failed Error: %s", i, cc, errs) | |
11206 | } | |
11207 | } else { | |
11208 | if IsEqual(errs, nil) { | |
11209 | t.Fatalf("Index: %d postcode_iso3166_alpha2=%s failed Error: %s", i, cc, errs) | |
11210 | } | |
11211 | } | |
11212 | } | |
11213 | } | |
11214 | } | |
11215 | ||
11216 | func TestPostCodeByIso3166Alpha2Field(t *testing.T) { | |
11217 | tests := []struct { | |
11218 | Value string `validate:"postcode_iso3166_alpha2_field=CountryCode"` | |
11219 | CountryCode interface{} | |
11220 | expected bool | |
11221 | }{ | |
11222 | {"ABC", "VN", false}, | |
11223 | {"700000", "VN", true}, | |
11224 | {"A1", "VN", false}, | |
11225 | {"EC1A 1BB", "GB", true}, | |
11226 | {"CF10 1B1H", "GB", false}, | |
11227 | {"00803", "VI", true}, | |
11228 | {"1234567", "VI", false}, | |
11229 | {"123456", "LC", false}, // not support regexp for post code | |
11230 | {"123456", "XX", false}, // not support country | |
11231 | } | |
11232 | ||
11233 | validate := New() | |
11234 | ||
11235 | for i, test := range tests { | |
11236 | errs := validate.Struct(test) | |
11237 | if test.expected { | |
11238 | if !IsEqual(errs, nil) { | |
11239 | t.Fatalf("Index: %d postcode_iso3166_alpha2_field=CountryCode failed Error: %s", i, errs) | |
11240 | } | |
11241 | } else { | |
11242 | if IsEqual(errs, nil) { | |
11243 | t.Fatalf("Index: %d postcode_iso3166_alpha2_field=CountryCode failed Error: %s", i, errs) | |
11244 | } | |
11245 | } | |
11246 | } | |
11247 | } | |
11248 | ||
11249 | func TestPostCodeByIso3166Alpha2Field_WrongField(t *testing.T) { | |
11250 | type test struct { | |
11251 | Value string `validate:"postcode_iso3166_alpha2_field=CountryCode"` | |
11252 | CountryCode1 interface{} | |
11253 | expected bool | |
11254 | } | |
11255 | ||
11256 | errs := New().Struct(test{"ABC", "VN", false}) | |
11257 | assert.NotEqual(t, nil, errs) | |
11258 | } | |
11259 | ||
11260 | func TestPostCodeByIso3166Alpha2Field_MissingParam(t *testing.T) { | |
11261 | type test struct { | |
11262 | Value string `validate:"postcode_iso3166_alpha2_field="` | |
11263 | CountryCode1 interface{} | |
11264 | expected bool | |
11265 | } | |
11266 | ||
11267 | errs := New().Struct(test{"ABC", "VN", false}) | |
11268 | assert.NotEqual(t, nil, errs) | |
11269 | } | |
11270 | ||
11271 | func TestPostCodeByIso3166Alpha2Field_InvalidKind(t *testing.T) { | |
11272 | type test struct { | |
11273 | Value string `validate:"postcode_iso3166_alpha2_field=CountryCode"` | |
11274 | CountryCode interface{} | |
11275 | expected bool | |
11276 | } | |
11277 | defer func() { _ = recover() }() | |
11278 | ||
11279 | _ = New().Struct(test{"ABC", 123, false}) | |
11280 | t.Errorf("Didn't panic as expected") | |
11281 | } |