diff --git a/baked_in.go b/baked_in.go index 2cc914f..70376ca 100644 --- a/baked_in.go +++ b/baked_in.go @@ -68,129 +68,131 @@ var ( // you can add, remove or even replace items to suite your needs, // or even disregard and use your own map if so desired. bakedInValidators = map[string]Func{ - "required": hasValue, - "required_if": requiredIf, - "required_unless": requiredUnless, - "required_with": requiredWith, - "required_with_all": requiredWithAll, - "required_without": requiredWithout, - "required_without_all": requiredWithoutAll, - "excluded_with": excludedWith, - "excluded_with_all": excludedWithAll, - "excluded_without": excludedWithout, - "excluded_without_all": excludedWithoutAll, - "isdefault": isDefault, - "len": hasLengthOf, - "min": hasMinOf, - "max": hasMaxOf, - "eq": isEq, - "ne": isNe, - "lt": isLt, - "lte": isLte, - "gt": isGt, - "gte": isGte, - "eqfield": isEqField, - "eqcsfield": isEqCrossStructField, - "necsfield": isNeCrossStructField, - "gtcsfield": isGtCrossStructField, - "gtecsfield": isGteCrossStructField, - "ltcsfield": isLtCrossStructField, - "ltecsfield": isLteCrossStructField, - "nefield": isNeField, - "gtefield": isGteField, - "gtfield": isGtField, - "ltefield": isLteField, - "ltfield": isLtField, - "fieldcontains": fieldContains, - "fieldexcludes": fieldExcludes, - "alpha": isAlpha, - "alphanum": isAlphanum, - "alphaunicode": isAlphaUnicode, - "alphanumunicode": isAlphanumUnicode, - "numeric": isNumeric, - "number": isNumber, - "hexadecimal": isHexadecimal, - "hexcolor": isHEXColor, - "rgb": isRGB, - "rgba": isRGBA, - "hsl": isHSL, - "hsla": isHSLA, - "e164": isE164, - "email": isEmail, - "url": isURL, - "uri": isURI, - "urn_rfc2141": isUrnRFC2141, // RFC 2141 - "file": isFile, - "base64": isBase64, - "base64url": isBase64URL, - "contains": contains, - "containsany": containsAny, - "containsrune": containsRune, - "excludes": excludes, - "excludesall": excludesAll, - "excludesrune": excludesRune, - "startswith": startsWith, - "endswith": endsWith, - "startsnotwith": startsNotWith, - "endsnotwith": endsNotWith, - "isbn": isISBN, - "isbn10": isISBN10, - "isbn13": isISBN13, - "eth_addr": isEthereumAddress, - "btc_addr": isBitcoinAddress, - "btc_addr_bech32": isBitcoinBech32Address, - "uuid": isUUID, - "uuid3": isUUID3, - "uuid4": isUUID4, - "uuid5": isUUID5, - "uuid_rfc4122": isUUIDRFC4122, - "uuid3_rfc4122": isUUID3RFC4122, - "uuid4_rfc4122": isUUID4RFC4122, - "uuid5_rfc4122": isUUID5RFC4122, - "ascii": isASCII, - "printascii": isPrintableASCII, - "multibyte": hasMultiByteCharacter, - "datauri": isDataURI, - "latitude": isLatitude, - "longitude": isLongitude, - "ssn": isSSN, - "ipv4": isIPv4, - "ipv6": isIPv6, - "ip": isIP, - "cidrv4": isCIDRv4, - "cidrv6": isCIDRv6, - "cidr": isCIDR, - "tcp4_addr": isTCP4AddrResolvable, - "tcp6_addr": isTCP6AddrResolvable, - "tcp_addr": isTCPAddrResolvable, - "udp4_addr": isUDP4AddrResolvable, - "udp6_addr": isUDP6AddrResolvable, - "udp_addr": isUDPAddrResolvable, - "ip4_addr": isIP4AddrResolvable, - "ip6_addr": isIP6AddrResolvable, - "ip_addr": isIPAddrResolvable, - "unix_addr": isUnixAddrResolvable, - "mac": isMAC, - "hostname": isHostnameRFC952, // RFC 952 - "hostname_rfc1123": isHostnameRFC1123, // RFC 1123 - "fqdn": isFQDN, - "unique": isUnique, - "oneof": isOneOf, - "html": isHTML, - "html_encoded": isHTMLEncoded, - "url_encoded": isURLEncoded, - "dir": isDir, - "json": isJSON, - "hostname_port": isHostnamePort, - "lowercase": isLowercase, - "uppercase": isUppercase, - "datetime": isDatetime, - "timezone": isTimeZone, - "iso3166_1_alpha2": isIso3166Alpha2, - "iso3166_1_alpha3": isIso3166Alpha3, - "iso3166_1_alpha_numeric": isIso3166AlphaNumeric, - "bcp47_language_tag": isBCP47LanguageTag, - "bic": isIsoBicFormat, + "required": hasValue, + "required_if": requiredIf, + "required_unless": requiredUnless, + "required_with": requiredWith, + "required_with_all": requiredWithAll, + "required_without": requiredWithout, + "required_without_all": requiredWithoutAll, + "excluded_with": excludedWith, + "excluded_with_all": excludedWithAll, + "excluded_without": excludedWithout, + "excluded_without_all": excludedWithoutAll, + "isdefault": isDefault, + "len": hasLengthOf, + "min": hasMinOf, + "max": hasMaxOf, + "eq": isEq, + "ne": isNe, + "lt": isLt, + "lte": isLte, + "gt": isGt, + "gte": isGte, + "eqfield": isEqField, + "eqcsfield": isEqCrossStructField, + "necsfield": isNeCrossStructField, + "gtcsfield": isGtCrossStructField, + "gtecsfield": isGteCrossStructField, + "ltcsfield": isLtCrossStructField, + "ltecsfield": isLteCrossStructField, + "nefield": isNeField, + "gtefield": isGteField, + "gtfield": isGtField, + "ltefield": isLteField, + "ltfield": isLtField, + "fieldcontains": fieldContains, + "fieldexcludes": fieldExcludes, + "alpha": isAlpha, + "alphanum": isAlphanum, + "alphaunicode": isAlphaUnicode, + "alphanumunicode": isAlphanumUnicode, + "numeric": isNumeric, + "number": isNumber, + "hexadecimal": isHexadecimal, + "hexcolor": isHEXColor, + "rgb": isRGB, + "rgba": isRGBA, + "hsl": isHSL, + "hsla": isHSLA, + "e164": isE164, + "email": isEmail, + "url": isURL, + "uri": isURI, + "urn_rfc2141": isUrnRFC2141, // RFC 2141 + "file": isFile, + "base64": isBase64, + "base64url": isBase64URL, + "contains": contains, + "containsany": containsAny, + "containsrune": containsRune, + "excludes": excludes, + "excludesall": excludesAll, + "excludesrune": excludesRune, + "startswith": startsWith, + "endswith": endsWith, + "startsnotwith": startsNotWith, + "endsnotwith": endsNotWith, + "isbn": isISBN, + "isbn10": isISBN10, + "isbn13": isISBN13, + "eth_addr": isEthereumAddress, + "btc_addr": isBitcoinAddress, + "btc_addr_bech32": isBitcoinBech32Address, + "uuid": isUUID, + "uuid3": isUUID3, + "uuid4": isUUID4, + "uuid5": isUUID5, + "uuid_rfc4122": isUUIDRFC4122, + "uuid3_rfc4122": isUUID3RFC4122, + "uuid4_rfc4122": isUUID4RFC4122, + "uuid5_rfc4122": isUUID5RFC4122, + "ascii": isASCII, + "printascii": isPrintableASCII, + "multibyte": hasMultiByteCharacter, + "datauri": isDataURI, + "latitude": isLatitude, + "longitude": isLongitude, + "ssn": isSSN, + "ipv4": isIPv4, + "ipv6": isIPv6, + "ip": isIP, + "cidrv4": isCIDRv4, + "cidrv6": isCIDRv6, + "cidr": isCIDR, + "tcp4_addr": isTCP4AddrResolvable, + "tcp6_addr": isTCP6AddrResolvable, + "tcp_addr": isTCPAddrResolvable, + "udp4_addr": isUDP4AddrResolvable, + "udp6_addr": isUDP6AddrResolvable, + "udp_addr": isUDPAddrResolvable, + "ip4_addr": isIP4AddrResolvable, + "ip6_addr": isIP6AddrResolvable, + "ip_addr": isIPAddrResolvable, + "unix_addr": isUnixAddrResolvable, + "mac": isMAC, + "hostname": isHostnameRFC952, // RFC 952 + "hostname_rfc1123": isHostnameRFC1123, // RFC 1123 + "fqdn": isFQDN, + "unique": isUnique, + "oneof": isOneOf, + "html": isHTML, + "html_encoded": isHTMLEncoded, + "url_encoded": isURLEncoded, + "dir": isDir, + "json": isJSON, + "hostname_port": isHostnamePort, + "lowercase": isLowercase, + "uppercase": isUppercase, + "datetime": isDatetime, + "timezone": isTimeZone, + "iso3166_1_alpha2": isIso3166Alpha2, + "iso3166_1_alpha3": isIso3166Alpha3, + "iso3166_1_alpha_numeric": isIso3166AlphaNumeric, + "bcp47_language_tag": isBCP47LanguageTag, + "postcode_iso3166_alpha2": isPostcodeByIso3166Alpha2, + "postcode_iso3166_alpha2_field": isPostcodeByIso3166Alpha2Field, + "bic": isIsoBicFormat, } ) @@ -1205,6 +1207,49 @@ func isEq(fl FieldLevel) bool { panic(fmt.Sprintf("Bad field type %T", field.Interface())) } +// isPostcodeByIso3166Alpha2 validates by value which is country code in iso 3166 alpha 2 +// example: `postcode_iso3166_alpha2=US` +func isPostcodeByIso3166Alpha2(fl FieldLevel) bool { + field := fl.Field() + param := fl.Param() + + reg, found := postCodeRegexDict[param] + if !found { + return false + } + + return reg.MatchString(field.String()) +} + +// isPostcodeByIso3166Alpha2 validates by field which represents for a value of country code in iso 3166 alpha 2 +// example: `postcode_iso3166_alpha2_field=CountryCode` +func isPostcodeByIso3166Alpha2Field(fl FieldLevel) bool { + field := fl.Field() + kind := field.Kind() + + params := parseOneOfParam2(fl.Param()) + + if len(params) != 1 { + return false + } + + currentField, kind, _, found := fl.GetStructFieldOKAdvanced2(fl.Parent(), params[0]) + if !found { + return false + } + + if kind != reflect.String { + panic(fmt.Sprintf("Bad field type %T", currentField.Interface())) + } + + reg, found := postCodeRegexDict[currentField.String()] + if !found { + return false + } + + return reg.MatchString(field.String()) +} + // IsBase64 is the validation function for validating if the current field's value is a valid base 64. func isBase64(fl FieldLevel) bool { return base64Regex.MatchString(fl.Field().String()) diff --git a/postcode_regexes.go b/postcode_regexes.go new file mode 100644 index 0000000..e7e7b68 --- /dev/null +++ b/postcode_regexes.go @@ -0,0 +1,173 @@ +package validator + +import "regexp" + +var postCodePatternDict = map[string]string{ + "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}$`, + "JE": `^JE\d[\dA-Z]?[ ]?\d[ABD-HJLN-UW-Z]{2}$`, + "GG": `^GY\d[\dA-Z]?[ ]?\d[ABD-HJLN-UW-Z]{2}$`, + "IM": `^IM\d[\dA-Z]?[ ]?\d[ABD-HJLN-UW-Z]{2}$`, + "US": `^\d{5}([ \-]\d{4})?$`, + "CA": `^[ABCEGHJKLMNPRSTVXY]\d[ABCEGHJ-NPRSTV-Z][ ]?\d[ABCEGHJ-NPRSTV-Z]\d$`, + "DE": `^\d{5}$`, + "JP": `^\d{3}-\d{4}$`, + "FR": `^\d{2}[ ]?\d{3}$`, + "AU": `^\d{4}$`, + "IT": `^\d{5}$`, + "CH": `^\d{4}$`, + "AT": `^\d{4}$`, + "ES": `^\d{5}$`, + "NL": `^\d{4}[ ]?[A-Z]{2}$`, + "BE": `^\d{4}$`, + "DK": `^\d{4}$`, + "SE": `^\d{3}[ ]?\d{2}$`, + "NO": `^\d{4}$`, + "BR": `^\d{5}[\-]?\d{3}$`, + "PT": `^\d{4}([\-]\d{3})?$`, + "FI": `^\d{5}$`, + "AX": `^22\d{3}$`, + "KR": `^\d{3}[\-]\d{3}$`, + "CN": `^\d{6}$`, + "TW": `^\d{3}(\d{2})?$`, + "SG": `^\d{6}$`, + "DZ": `^\d{5}$`, + "AD": `^AD\d{3}$`, + "AR": `^([A-HJ-NP-Z])?\d{4}([A-Z]{3})?$`, + "AM": `^(37)?\d{4}$`, + "AZ": `^\d{4}$`, + "BH": `^((1[0-2]|[2-9])\d{2})?$`, + "BD": `^\d{4}$`, + "BB": `^(BB\d{5})?$`, + "BY": `^\d{6}$`, + "BM": `^[A-Z]{2}[ ]?[A-Z0-9]{2}$`, + "BA": `^\d{5}$`, + "IO": `^BBND 1ZZ$`, + "BN": `^[A-Z]{2}[ ]?\d{4}$`, + "BG": `^\d{4}$`, + "KH": `^\d{5}$`, + "CV": `^\d{4}$`, + "CL": `^\d{7}$`, + "CR": `^\d{4,5}|\d{3}-\d{4}$`, + "HR": `^\d{5}$`, + "CY": `^\d{4}$`, + "CZ": `^\d{3}[ ]?\d{2}$`, + "DO": `^\d{5}$`, + "EC": `^([A-Z]\d{4}[A-Z]|(?:[A-Z]{2})?\d{6})?$`, + "EG": `^\d{5}$`, + "EE": `^\d{5}$`, + "FO": `^\d{3}$`, + "GE": `^\d{4}$`, + "GR": `^\d{3}[ ]?\d{2}$`, + "GL": `^39\d{2}$`, + "GT": `^\d{5}$`, + "HT": `^\d{4}$`, + "HN": `^(?:\d{5})?$`, + "HU": `^\d{4}$`, + "IS": `^\d{3}$`, + "IN": `^\d{6}$`, + "ID": `^\d{5}$`, + "IL": `^\d{5}$`, + "JO": `^\d{5}$`, + "KZ": `^\d{6}$`, + "KE": `^\d{5}$`, + "KW": `^\d{5}$`, + "LA": `^\d{5}$`, + "LV": `^\d{4}$`, + "LB": `^(\d{4}([ ]?\d{4})?)?$`, + "LI": `^(948[5-9])|(949[0-7])$`, + "LT": `^\d{5}$`, + "LU": `^\d{4}$`, + "MK": `^\d{4}$`, + "MY": `^\d{5}$`, + "MV": `^\d{5}$`, + "MT": `^[A-Z]{3}[ ]?\d{2,4}$`, + "MU": `^(\d{3}[A-Z]{2}\d{3})?$`, + "MX": `^\d{5}$`, + "MD": `^\d{4}$`, + "MC": `^980\d{2}$`, + "MA": `^\d{5}$`, + "NP": `^\d{5}$`, + "NZ": `^\d{4}$`, + "NI": `^((\d{4}-)?\d{3}-\d{3}(-\d{1})?)?$`, + "NG": `^(\d{6})?$`, + "OM": `^(PC )?\d{3}$`, + "PK": `^\d{5}$`, + "PY": `^\d{4}$`, + "PH": `^\d{4}$`, + "PL": `^\d{2}-\d{3}$`, + "PR": `^00[679]\d{2}([ \-]\d{4})?$`, + "RO": `^\d{6}$`, + "RU": `^\d{6}$`, + "SM": `^4789\d$`, + "SA": `^\d{5}$`, + "SN": `^\d{5}$`, + "SK": `^\d{3}[ ]?\d{2}$`, + "SI": `^\d{4}$`, + "ZA": `^\d{4}$`, + "LK": `^\d{5}$`, + "TJ": `^\d{6}$`, + "TH": `^\d{5}$`, + "TN": `^\d{4}$`, + "TR": `^\d{5}$`, + "TM": `^\d{6}$`, + "UA": `^\d{5}$`, + "UY": `^\d{5}$`, + "UZ": `^\d{6}$`, + "VA": `^00120$`, + "VE": `^\d{4}$`, + "ZM": `^\d{5}$`, + "AS": `^96799$`, + "CC": `^6799$`, + "CK": `^\d{4}$`, + "RS": `^\d{6}$`, + "ME": `^8\d{4}$`, + "CS": `^\d{5}$`, + "YU": `^\d{5}$`, + "CX": `^6798$`, + "ET": `^\d{4}$`, + "FK": `^FIQQ 1ZZ$`, + "NF": `^2899$`, + "FM": `^(9694[1-4])([ \-]\d{4})?$`, + "GF": `^9[78]3\d{2}$`, + "GN": `^\d{3}$`, + "GP": `^9[78][01]\d{2}$`, + "GS": `^SIQQ 1ZZ$`, + "GU": `^969[123]\d([ \-]\d{4})?$`, + "GW": `^\d{4}$`, + "HM": `^\d{4}$`, + "IQ": `^\d{5}$`, + "KG": `^\d{6}$`, + "LR": `^\d{4}$`, + "LS": `^\d{3}$`, + "MG": `^\d{3}$`, + "MH": `^969[67]\d([ \-]\d{4})?$`, + "MN": `^\d{6}$`, + "MP": `^9695[012]([ \-]\d{4})?$`, + "MQ": `^9[78]2\d{2}$`, + "NC": `^988\d{2}$`, + "NE": `^\d{4}$`, + "VI": `^008(([0-4]\d)|(5[01]))([ \-]\d{4})?$`, + "VN": `^[0-9]{1,6}$`, + "PF": `^987\d{2}$`, + "PG": `^\d{3}$`, + "PM": `^9[78]5\d{2}$`, + "PN": `^PCRN 1ZZ$`, + "PW": `^96940$`, + "RE": `^9[78]4\d{2}$`, + "SH": `^(ASCN|STHL) 1ZZ$`, + "SJ": `^\d{4}$`, + "SO": `^\d{5}$`, + "SZ": `^[HLMS]\d{3}$`, + "TC": `^TKCA 1ZZ$`, + "WF": `^986\d{2}$`, + "XK": `^\d{5}$`, + "YT": `^976\d{2}$`, +} + +var postCodeRegexDict = map[string]*regexp.Regexp{} + +func init() { + for countryCode, pattern := range postCodePatternDict { + postCodeRegexDict[countryCode] = regexp.MustCompile(pattern) + } +} diff --git a/translations/en/en.go b/translations/en/en.go index 1fdea95..3bbca51 100644 --- a/translations/en/en.go +++ b/translations/en/en.go @@ -16,7 +16,6 @@ import ( // RegisterDefaultTranslations registers a set of default translations // for all built in tag's in validator; you may add your own as desired. func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (err error) { - translations := []struct { tag string translation string @@ -32,7 +31,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er { tag: "len", customRegisFunc: func(ut ut.Translator) (err error) { - if err = ut.Add("len-string", "{0} must be {1} in length", false); err != nil { return } @@ -61,10 +59,8 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er } return - }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - var err error var t string @@ -123,7 +119,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er { tag: "min", customRegisFunc: func(ut ut.Translator) (err error) { - if err = ut.Add("min-string", "{0} must be at least {1} in length", false); err != nil { return } @@ -152,10 +147,8 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er } return - }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - var err error var t string @@ -214,7 +207,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er { tag: "max", customRegisFunc: func(ut ut.Translator) (err error) { - if err = ut.Add("max-string", "{0} must be a maximum of {1} in length", false); err != nil { return } @@ -243,10 +235,8 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er } return - }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - var err error var t string @@ -307,7 +297,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} is not equal to {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { fmt.Printf("warning: error translating FieldError: %#v", fe) @@ -322,7 +311,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} should not be equal to {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { fmt.Printf("warning: error translating FieldError: %#v", fe) @@ -335,7 +323,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er { tag: "lt", customRegisFunc: func(ut ut.Translator) (err error) { - if err = ut.Add("lt-string", "{0} must be less than {1} in length", false); err != nil { return } @@ -369,10 +356,8 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er } return - }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - var err error var t string var f64 float64 @@ -380,7 +365,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er var kind reflect.Kind fn := func() (err error) { - if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } @@ -456,7 +440,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er { tag: "lte", customRegisFunc: func(ut ut.Translator) (err error) { - if err = ut.Add("lte-string", "{0} must be at maximum {1} in length", false); err != nil { return } @@ -492,7 +475,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - var err error var t string var f64 float64 @@ -500,7 +482,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er var kind reflect.Kind fn := func() (err error) { - if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } @@ -576,7 +557,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er { tag: "gt", customRegisFunc: func(ut ut.Translator) (err error) { - if err = ut.Add("gt-string", "{0} must be greater than {1} in length", false); err != nil { return } @@ -612,7 +592,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - var err error var t string var f64 float64 @@ -620,7 +599,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er var kind reflect.Kind fn := func() (err error) { - if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } @@ -696,7 +674,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er { tag: "gte", customRegisFunc: func(ut ut.Translator) (err error) { - if err = ut.Add("gte-string", "{0} must be at least {1} in length", false); err != nil { return } @@ -732,7 +709,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - var err error var t string var f64 float64 @@ -740,7 +716,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er var kind reflect.Kind fn := func() (err error) { - if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } @@ -818,7 +793,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} must be equal to {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) @@ -833,7 +807,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} must be equal to {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) @@ -848,7 +821,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} cannot be equal to {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) @@ -863,7 +835,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} must be greater than {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) @@ -878,7 +849,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} must be greater than or equal to {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) @@ -893,7 +863,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} must be less than {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) @@ -908,7 +877,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} must be less than or equal to {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) @@ -923,7 +891,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} cannot be equal to {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) @@ -938,7 +905,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} must be greater than {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) @@ -953,7 +919,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} must be greater than or equal to {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) @@ -968,7 +933,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} must be less than {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) @@ -983,7 +947,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} must be less than or equal to {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) @@ -1073,7 +1036,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} must contain the text '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) @@ -1088,7 +1050,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} must contain at least one of the following characters '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) @@ -1103,7 +1064,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} cannot contain the text '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) @@ -1118,7 +1078,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} cannot contain any of the following characters '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) @@ -1133,7 +1092,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} cannot contain the following '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) @@ -1325,8 +1283,8 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er tag: "json", translation: "{0} must be a valid json string", override: false, - }, - { + }, + { tag: "lowercase", translation: "{0} must be a lowercase string", override: false, @@ -1341,7 +1299,34 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} does not match the {1} format", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) + if err != nil { + log.Printf("warning: error translating FieldError: %#v", fe) + return fe.(error).Error() + } + return t + }, + }, + { + tag: "postcode_iso3166_alpha2", + translation: "{0} does not match postcode format of {1} country", + override: false, + customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) + if err != nil { + log.Printf("warning: error translating FieldError: %#v", fe) + return fe.(error).Error() + } + + return t + }, + }, + { + tag: "postcode_iso3166_alpha2_field", + translation: "{0} does not match postcode format of country in {1} field", + override: false, + customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) @@ -1356,17 +1341,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er for _, t := range translations { if t.customTransFunc != nil && t.customRegisFunc != nil { - err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, t.customTransFunc) - } else if t.customTransFunc != nil && t.customRegisFunc == nil { - err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), t.customTransFunc) - } else if t.customTransFunc == nil && t.customRegisFunc != nil { - err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, translateFunc) - } else { err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), translateFunc) } @@ -1380,21 +1359,16 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er } func registrationFunc(tag string, translation string, override bool) validator.RegisterTranslationsFunc { - return func(ut ut.Translator) (err error) { - if err = ut.Add(tag, translation, override); err != nil { return } return - } - } func translateFunc(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) diff --git a/translations/en/en_test.go b/translations/en/en_test.go index 2b113c6..fd8df77 100644 --- a/translations/en/en_test.go +++ b/translations/en/en_test.go @@ -11,7 +11,6 @@ import ( ) func TestTranslations(t *testing.T) { - eng := english.New() uni := ut.New(eng, eng) trans, _ := uni.GetTranslator("en") @@ -145,6 +144,9 @@ func TestTranslations(t *testing.T) { LowercaseString string `validate:"lowercase"` UppercaseString string `validate:"uppercase"` Datetime string `validate:"datetime=2006-01-02"` + PostCode string `validate:"postcode_iso3166_alpha2=SG"` + PostCodeCountry string + PostCodeByField string `validate:"postcode_iso3166_alpha2_field=PostCodeCountry"` } var test Test @@ -656,6 +658,14 @@ func TestTranslations(t *testing.T) { ns: "Test.Datetime", expected: "Datetime does not match the 2006-01-02 format", }, + { + ns: "Test.PostCode", + expected: "PostCode does not match postcode format of SG country", + }, + { + ns: "Test.PostCodeByField", + expected: "PostCodeByField does not match postcode format of country in PostCodeCountry field", + }, } for _, tt := range tests { @@ -672,5 +682,4 @@ func TestTranslations(t *testing.T) { NotEqual(t, fe, nil) Equal(t, tt.expected, fe.Translate(trans)) } - } diff --git a/validator_test.go b/validator_test.go index 19dac53..be967d4 100644 --- a/validator_test.go +++ b/validator_test.go @@ -14,6 +14,7 @@ import ( "testing" "time" + "github.com/go-playground/assert/v2" . "github.com/go-playground/assert/v2" "github.com/go-playground/locales/en" "github.com/go-playground/locales/fr" @@ -108,7 +109,6 @@ type TestSlice struct { } func AssertError(t *testing.T, err error, nsKey, structNsKey, field, structField, expectedTag string) { - errs := err.(ValidationErrors) found := false @@ -150,7 +150,6 @@ func AssertDeepError(t *testing.T, err error, nsKey, structNsKey, field, structF } func getError(err error, nsKey, structNsKey string) FieldError { - errs := err.(ValidationErrors) var fe FieldError @@ -170,7 +169,6 @@ type valuer struct { } func (v valuer) Value() (driver.Value, error) { - if v.Name == "errorme" { panic("SQL Driver Valuer error: some kind of error") // return nil, errors.New("some kind of error") @@ -189,7 +187,6 @@ type MadeUpCustomType struct { } func ValidateCustomType(field reflect.Value) interface{} { - if cust, ok := field.Interface().(MadeUpCustomType); ok { if len(cust.FirstName) == 0 || len(cust.LastName) == 0 { @@ -203,7 +200,6 @@ func ValidateCustomType(field reflect.Value) interface{} { } func OverrideIntTypeForSomeReason(field reflect.Value) interface{} { - if i, ok := field.Interface().(int); ok { if i == 1 { return "1" @@ -223,7 +219,6 @@ type CustomMadeUpStruct struct { } func ValidateValuerType(field reflect.Value) interface{} { - if valuer, ok := field.Interface().(driver.Valuer); ok { val, err := valuer.Value() @@ -261,7 +256,6 @@ type TestStruct struct { } func StructValidationTestStructSuccess(sl StructLevel) { - st := sl.Current().Interface().(TestStruct) if st.String != "good value" { @@ -270,7 +264,6 @@ func StructValidationTestStructSuccess(sl StructLevel) { } func StructValidationTestStruct(sl StructLevel) { - st := sl.Current().Interface().(TestStruct) if st.String != "bad value" { @@ -279,7 +272,6 @@ func StructValidationTestStruct(sl StructLevel) { } func StructValidationNoTestStructCustomName(sl StructLevel) { - st := sl.Current().Interface().(TestStruct) if st.String != "bad value" { @@ -288,7 +280,6 @@ func StructValidationNoTestStructCustomName(sl StructLevel) { } func StructValidationTestStructInvalid(sl StructLevel) { - st := sl.Current().Interface().(TestStruct) if st.String != "bad value" { @@ -297,7 +288,6 @@ func StructValidationTestStructInvalid(sl StructLevel) { } func StructValidationTestStructReturnValidationErrors(sl StructLevel) { - s := sl.Current().Interface().(TestStructReturnValidationErrors) errs := sl.Validator().Struct(s.Inner1.Inner2) @@ -309,7 +299,6 @@ func StructValidationTestStructReturnValidationErrors(sl StructLevel) { } func StructValidationTestStructReturnValidationErrors2(sl StructLevel) { - s := sl.Current().Interface().(TestStructReturnValidationErrors) errs := sl.Validator().Struct(s.Inner1.Inner2) @@ -337,7 +326,6 @@ type StructLevelInvalidErr struct { } func StructLevelInvalidError(sl StructLevel) { - top := sl.Top().Interface().(StructLevelInvalidErr) s := sl.Current().Interface().(StructLevelInvalidErr) @@ -359,7 +347,6 @@ func float64Ptr(v float64) *float64 { } func TestStructLevelInvalidError(t *testing.T) { - validate := New() validate.RegisterStructValidation(StructLevelInvalidError, StructLevelInvalidErr{}) @@ -383,7 +370,6 @@ func TestStructLevelInvalidError(t *testing.T) { } func TestNameNamespace(t *testing.T) { - type Inner2Namespace struct { String []string `validate:"dive,required" json:"JSONString"` } @@ -432,7 +418,6 @@ func TestNameNamespace(t *testing.T) { } func TestAnonymous(t *testing.T) { - validate := New() validate.RegisterTagNameFunc(func(fld reflect.StructField) string { name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] @@ -500,7 +485,6 @@ func TestAnonymous(t *testing.T) { } func TestAnonymousSameStructDifferentTags(t *testing.T) { - validate := New() validate.RegisterTagNameFunc(func(fld reflect.StructField) string { name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] @@ -545,7 +529,6 @@ func TestAnonymousSameStructDifferentTags(t *testing.T) { } func TestStructLevelReturnValidationErrors(t *testing.T) { - validate := New() validate.RegisterStructValidation(StructValidationTestStructReturnValidationErrors, TestStructReturnValidationErrors{}) @@ -575,7 +558,6 @@ func TestStructLevelReturnValidationErrors(t *testing.T) { } func TestStructLevelReturnValidationErrorsWithJSON(t *testing.T) { - validate := New() validate.RegisterTagNameFunc(func(fld reflect.StructField) string { name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] @@ -632,7 +614,6 @@ func TestStructLevelReturnValidationErrorsWithJSON(t *testing.T) { } func TestStructLevelValidations(t *testing.T) { - v1 := New() v1.RegisterStructValidation(StructValidationTestStruct, TestStruct{}) @@ -666,7 +647,6 @@ func TestStructLevelValidations(t *testing.T) { } func TestAliasTags(t *testing.T) { - validate := New() validate.RegisterAlias("iscoloralias", "hexcolor|rgb|rgba|hsl|hsla") @@ -714,7 +694,6 @@ func TestAliasTags(t *testing.T) { } func TestNilValidator(t *testing.T) { - type TestStruct struct { Test string `validate:"required"` } @@ -724,7 +703,6 @@ func TestNilValidator(t *testing.T) { var val *Validate fn := func(fl FieldLevel) bool { - return fl.Parent().String() == fl.Field().String() } @@ -1971,7 +1949,6 @@ func TestCrossStructEqFieldValidation(t *testing.T) { } func TestCrossNamespaceFieldValidation(t *testing.T) { - type SliceStruct struct { Name string } @@ -2209,7 +2186,6 @@ func TestCrossNamespaceFieldValidation(t *testing.T) { } func TestExistsValidation(t *testing.T) { - jsonText := "{ \"truthiness2\": true }" type Thing struct { @@ -2240,7 +2216,6 @@ func TestExistsValidation(t *testing.T) { } func TestSQLValue2Validation(t *testing.T) { - validate := New() validate.RegisterCustomTypeFunc(ValidateValuerType, valuer{}, (*driver.Valuer)(nil), sql.NullString{}, sql.NullInt64{}, sql.NullBool{}, sql.NullFloat64{}) validate.RegisterCustomTypeFunc(ValidateCustomType, MadeUpCustomType{}) @@ -2291,7 +2266,6 @@ func TestSQLValue2Validation(t *testing.T) { } func TestSQLValueValidation(t *testing.T) { - validate := New() validate.RegisterCustomTypeFunc(ValidateValuerType, (*driver.Valuer)(nil), valuer{}) validate.RegisterCustomTypeFunc(ValidateCustomType, MadeUpCustomType{}) @@ -2969,7 +2943,6 @@ func TestUnixAddrValidation(t *testing.T) { } func TestSliceMapArrayChanFuncPtrInterfaceRequiredValidation(t *testing.T) { - validate := New() var m map[string]string @@ -3047,7 +3020,6 @@ func TestSliceMapArrayChanFuncPtrInterfaceRequiredValidation(t *testing.T) { } func TestDatePtrValidationIssueValidation(t *testing.T) { - type Test struct { LastViewed *time.Time Reminder *time.Time @@ -3099,7 +3071,6 @@ func TestBadKeyValidation(t *testing.T) { } func TestInterfaceErrValidation(t *testing.T) { - var v2 interface{} = 1 var v1 interface{} = v2 @@ -3273,7 +3244,6 @@ func TestInterfaceErrValidation(t *testing.T) { } func TestMapDiveValidation(t *testing.T) { - validate := New() n := map[int]interface{}{0: nil} @@ -3396,7 +3366,6 @@ func TestMapDiveValidation(t *testing.T) { } func TestArrayDiveValidation(t *testing.T) { - validate := New() arr := []string{"ok", "", "ok"} @@ -4405,7 +4374,6 @@ func TestISBN10Validation(t *testing.T) { } func TestExcludesRuneValidation(t *testing.T) { - tests := []struct { Value string `validate:"excludesrune=☻"` Tag string @@ -4433,7 +4401,6 @@ func TestExcludesRuneValidation(t *testing.T) { } func TestExcludesAllValidation(t *testing.T) { - tests := []struct { Value string `validate:"excludesall=@!{}[]"` Tag string @@ -4479,7 +4446,6 @@ func TestExcludesAllValidation(t *testing.T) { } func TestExcludesValidation(t *testing.T) { - tests := []struct { Value string `validate:"excludes=@"` Tag string @@ -4507,7 +4473,6 @@ func TestExcludesValidation(t *testing.T) { } func TestContainsRuneValidation(t *testing.T) { - tests := []struct { Value string `validate:"containsrune=☻"` Tag string @@ -4535,7 +4500,6 @@ func TestContainsRuneValidation(t *testing.T) { } func TestContainsAnyValidation(t *testing.T) { - tests := []struct { Value string `validate:"containsany=@!{}[]"` Tag string @@ -4563,7 +4527,6 @@ func TestContainsAnyValidation(t *testing.T) { } func TestContainsValidation(t *testing.T) { - tests := []struct { Value string `validate:"contains=@"` Tag string @@ -5149,7 +5112,6 @@ func TestOneOfValidation(t *testing.T) { } func TestBase64Validation(t *testing.T) { - validate := New() s := "dW5pY29ybg==" @@ -5253,7 +5215,6 @@ func TestFileValidation(t *testing.T) { } func TestEthereumAddressValidation(t *testing.T) { - validate := New() tests := []struct { @@ -5307,7 +5268,6 @@ func TestEthereumAddressValidation(t *testing.T) { } func TestBitcoinAddressValidation(t *testing.T) { - validate := New() tests := []struct { @@ -5417,7 +5377,6 @@ func TestBitcoinAddressValidation(t *testing.T) { } func TestBitcoinBech32AddressValidation(t *testing.T) { - validate := New() tests := []struct { @@ -5468,7 +5427,6 @@ func TestBitcoinBech32AddressValidation(t *testing.T) { } func TestNoStructLevelValidation(t *testing.T) { - type Inner struct { Test string `validate:"len=5"` } @@ -5500,7 +5458,6 @@ func TestNoStructLevelValidation(t *testing.T) { } func TestStructOnlyValidation(t *testing.T) { - type Inner struct { Test string `validate:"len=5"` } @@ -6566,7 +6523,6 @@ func TestValidateByTagAndValue(t *testing.T) { Equal(t, errs, nil) fn := func(fl FieldLevel) bool { - return fl.Parent().String() == fl.Field().String() } @@ -6584,9 +6540,7 @@ func TestValidateByTagAndValue(t *testing.T) { } func TestAddFunctions(t *testing.T) { - fn := func(fl FieldLevel) bool { - return true } @@ -6615,7 +6569,6 @@ func TestAddFunctions(t *testing.T) { } func TestChangeTag(t *testing.T) { - validate := New() validate.SetTagName("val") @@ -7262,8 +7215,7 @@ func TestIsLte(t *testing.T) { } func TestUrnRFC2141(t *testing.T) { - - var tests = []struct { + tests := []struct { param string expected bool }{ @@ -7339,8 +7291,7 @@ func TestUrnRFC2141(t *testing.T) { } func TestUrl(t *testing.T) { - - var tests = []struct { + tests := []struct { param string expected bool }{ @@ -7407,8 +7358,7 @@ func TestUrl(t *testing.T) { } func TestUri(t *testing.T) { - - var tests = []struct { + tests := []struct { param string expected bool }{ @@ -7474,7 +7424,6 @@ func TestUri(t *testing.T) { } func TestOrTag(t *testing.T) { - validate := New() s := "rgba(0,31,255,0.5)" @@ -7504,7 +7453,7 @@ func TestOrTag(t *testing.T) { Equal(t, errs, nil) s = "green" - errs = validate.Var(s, "eq=|eq=blue,rgb|rgba") //should fail on first validation block + errs = validate.Var(s, "eq=|eq=blue,rgb|rgba") // should fail on first validation block NotEqual(t, errs, nil) ve := errs.(ValidationErrors) Equal(t, len(ve), 1) @@ -7517,7 +7466,6 @@ func TestOrTag(t *testing.T) { v2 := New() v2.RegisterTagNameFunc(func(fld reflect.StructField) string { - name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] if name == "-" { @@ -7542,7 +7490,6 @@ func TestOrTag(t *testing.T) { } func TestHsla(t *testing.T) { - validate := New() s := "hsla(360,100%,100%,1)" @@ -7589,7 +7536,6 @@ func TestHsla(t *testing.T) { } func TestHsl(t *testing.T) { - validate := New() s := "hsl(360,100%,50%)" @@ -7627,7 +7573,6 @@ func TestHsl(t *testing.T) { } func TestRgba(t *testing.T) { - validate := New() s := "rgba(0,31,255,0.5)" @@ -7673,7 +7618,6 @@ func TestRgba(t *testing.T) { } func TestRgb(t *testing.T) { - validate := New() s := "rgb(0,31,255)" @@ -7715,7 +7659,6 @@ func TestRgb(t *testing.T) { } func TestEmail(t *testing.T) { - validate := New() s := "test@mail.com" @@ -7783,7 +7726,6 @@ func TestEmail(t *testing.T) { } func TestHexColor(t *testing.T) { - validate := New() s := "#fff" @@ -7811,7 +7753,6 @@ func TestHexColor(t *testing.T) { } func TestHexadecimal(t *testing.T) { - validate := New() s := "ff0044" @@ -7838,7 +7779,6 @@ func TestHexadecimal(t *testing.T) { } func TestNumber(t *testing.T) { - validate := New() s := "1" @@ -7886,7 +7826,6 @@ func TestNumber(t *testing.T) { } func TestNumeric(t *testing.T) { - validate := New() s := "1" @@ -7929,7 +7868,6 @@ func TestNumeric(t *testing.T) { } func TestAlphaNumeric(t *testing.T) { - validate := New() s := "abcd123" @@ -7947,7 +7885,6 @@ func TestAlphaNumeric(t *testing.T) { } func TestAlpha(t *testing.T) { - validate := New() s := "abcd" @@ -7977,11 +7914,9 @@ func TestAlpha(t *testing.T) { errs = validate.Var(1, "alpha") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "alpha") - } func TestStructStringValidation(t *testing.T) { - validate := New() tSuccess := &TestString{ @@ -8063,7 +7998,6 @@ func TestStructStringValidation(t *testing.T) { } func TestStructInt32Validation(t *testing.T) { - type TestInt32 struct { Required int `validate:"required"` Len int `validate:"len=10"` @@ -8127,7 +8061,6 @@ func TestStructInt32Validation(t *testing.T) { } func TestStructUint64Validation(t *testing.T) { - validate := New() tSuccess := &TestUint64{ @@ -8167,7 +8100,6 @@ func TestStructUint64Validation(t *testing.T) { } func TestStructFloat64Validation(t *testing.T) { - validate := New() tSuccess := &TestFloat64{ @@ -8207,7 +8139,6 @@ func TestStructFloat64Validation(t *testing.T) { } func TestStructSliceValidation(t *testing.T) { - validate := New() tSuccess := &TestSlice{ @@ -8257,11 +8188,9 @@ func TestStructSliceValidation(t *testing.T) { _, ok := fe.Value().([]int) Equal(t, ok, true) - } func TestInvalidStruct(t *testing.T) { - validate := New() s := &SubTest{ @@ -8286,7 +8215,6 @@ func TestInvalidStruct(t *testing.T) { } func TestInvalidValidatorFunction(t *testing.T) { - validate := New() s := &SubTest{ @@ -8297,7 +8225,6 @@ func TestInvalidValidatorFunction(t *testing.T) { } func TestCustomFieldName(t *testing.T) { - validate := New() validate.RegisterTagNameFunc(func(fld reflect.StructField) string { name := strings.SplitN(fld.Tag.Get("schema"), ",", 2)[0] @@ -8341,7 +8268,6 @@ func TestCustomFieldName(t *testing.T) { } func TestMutipleRecursiveExtractStructCache(t *testing.T) { - validate := New() type Recursive struct { @@ -8358,7 +8284,6 @@ func TestMutipleRecursiveExtractStructCache(t *testing.T) { ptr := fmt.Sprintf("%p", sc) for i := 0; i < 100; i++ { - go func() { <-proceed sc := validate.extractStructCache(current, name) @@ -8371,7 +8296,6 @@ func TestMutipleRecursiveExtractStructCache(t *testing.T) { // Thanks @robbrockbank, see https://github.com/go-playground/validator/issues/249 func TestPointerAndOmitEmpty(t *testing.T) { - validate := New() type Test struct { @@ -8417,7 +8341,6 @@ func TestPointerAndOmitEmpty(t *testing.T) { } func TestRequired(t *testing.T) { - validate := New() validate.RegisterTagNameFunc(func(fld reflect.StructField) string { name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] @@ -8441,7 +8364,6 @@ func TestRequired(t *testing.T) { } func TestBoolEqual(t *testing.T) { - validate := New() type Test struct { @@ -8469,16 +8391,13 @@ func TestTranslations(t *testing.T) { validate := New() err := validate.RegisterTranslation("required", trans, func(ut ut.Translator) (err error) { - // using this stype because multiple translation may have to be added for the full translation if err = ut.Add("required", "{0} is a required field", false); err != nil { return } return - }, func(ut ut.Translator, fe FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field()) if err != nil { fmt.Printf("warning: error translating FieldError: %#v", fe.(*fieldError)) @@ -8491,16 +8410,13 @@ func TestTranslations(t *testing.T) { err = validate.RegisterTranslation("required", fr, func(ut ut.Translator) (err error) { - // using this stype because multiple translation may have to be added for the full translation if err = ut.Add("required", "{0} est un champ obligatoire", false); err != nil { return } return - }, func(ut ut.Translator, fe FieldError) string { - t, transErr := ut.T(fe.Tag(), fe.Field()) if transErr != nil { fmt.Printf("warning: error translating FieldError: %#v", fe.(*fieldError)) @@ -8578,16 +8494,13 @@ func TestTranslationErrors(t *testing.T) { validate := New() err = validate.RegisterTranslation("required", trans, func(ut ut.Translator) (err error) { - // using this stype because multiple translation may have to be added for the full translation if err = ut.Add("required", "{0} is a required field", false); err != nil { return } return - }, func(ut ut.Translator, fe FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field()) if err != nil { fmt.Printf("warning: error translating FieldError: %#v", fe.(*fieldError)) @@ -8602,7 +8515,6 @@ func TestTranslationErrors(t *testing.T) { } func TestStructFiltered(t *testing.T) { - p1 := func(ns []byte) bool { if bytes.HasSuffix(ns, []byte("NoTag")) || bytes.HasSuffix(ns, []byte("Required")) { return false @@ -8768,7 +8680,6 @@ func TestStructFiltered(t *testing.T) { } func TestRequiredPtr(t *testing.T) { - type Test struct { Bool *bool `validate:"required"` } @@ -8902,7 +8813,6 @@ func TestAlphaUnicodeValidation(t *testing.T) { } func TestAlphanumericUnicodeValidation(t *testing.T) { - tests := []struct { param string expected bool @@ -8945,7 +8855,6 @@ func TestAlphanumericUnicodeValidation(t *testing.T) { } func TestArrayStructNamespace(t *testing.T) { - validate := New() validate.RegisterTagNameFunc(func(fld reflect.StructField) string { name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] @@ -8974,7 +8883,6 @@ func TestArrayStructNamespace(t *testing.T) { } func TestMapStructNamespace(t *testing.T) { - validate := New() validate.RegisterTagNameFunc(func(fld reflect.StructField) string { name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] @@ -9655,7 +9563,6 @@ func TestURLEncodedValidation(t *testing.T) { } func TestKeys(t *testing.T) { - type Test struct { Test1 map[string]string `validate:"gt=0,dive,keys,eq=testkey,endkeys,eq=testval" json:"test1"` Test2 map[int]int `validate:"gt=0,dive,keys,eq=3,endkeys,eq=4" json:"test2"` @@ -9824,7 +9731,6 @@ func TestKeysCustomValidation(t *testing.T) { } func TestKeyOrs(t *testing.T) { - type Test struct { Test1 map[string]string `validate:"gt=0,dive,keys,eq=testkey|eq=testkeyok,endkeys,eq=testval" json:"test1"` } @@ -10602,7 +10508,6 @@ func TestRequiredWithAll(t *testing.T) { } func TestRequiredWithout(t *testing.T) { - type Inner struct { Field *string } @@ -10668,7 +10573,6 @@ func TestRequiredWithout(t *testing.T) { } func TestRequiredWithoutAll(t *testing.T) { - fieldVal := "test" test := struct { Field1 string `validate:"omitempty" json:"field_1"` @@ -10725,7 +10629,6 @@ func TestLookup(t *testing.T) { } func TestAbilityToValidateNils(t *testing.T) { - type TestStruct struct { Test *string `validate:"nil"` } @@ -10867,7 +10770,6 @@ func TestJSONValidation(t *testing.T) { } func Test_hostnameport_validator(t *testing.T) { - type Host struct { Addr string `validate:"hostname_port"` } @@ -10969,7 +10871,6 @@ func TestUppercaseValidation(t *testing.T) { PanicMatches(t, func() { _ = validate.Var(2, "uppercase") }, "Bad field type int") - } func TestDatetimeValidation(t *testing.T) { @@ -11225,42 +11126,154 @@ func TestBCP47LanguageTagValidation(t *testing.T) { } func TestBicIsoFormatValidation(t *testing.T) { - tests := []struct { - value string `validate:"bic"` - tag string - expected bool - }{ - {"SBICKEN1345", "bic", true}, - {"SBICKEN1", "bic", true}, - {"SBICKENY", "bic", true}, - {"SBICKEN1YYP", "bic", true}, - {"SBIC23NXXX", "bic", false}, - {"S23CKENXXXX", "bic", false}, - {"SBICKENXX", "bic", false}, - {"SBICKENXX9", "bic", false}, - {"SBICKEN13458", "bic", false}, - {"SBICKEN", "bic", false}, - } - - validate := New() - - for i, test := range tests { - - errs := validate.Var(test.value, test.tag) - - if test.expected { - if !IsEqual(errs, nil) { - t.Fatalf("Index: %d bic failed Error: %s", i, errs) - } - } else { - if IsEqual(errs, nil) { - t.Fatalf("Index: %d bic failed Error: %s", i, errs) - } else { - val := getError(errs, "", "") - if val.Tag() != "bic" { - t.Fatalf("Index: %d bic failed Error: %s", i, errs) - } - } - } - } -} + tests := []struct { + value string `validate:"bic"` + tag string + expected bool + }{ + {"SBICKEN1345", "bic", true}, + {"SBICKEN1", "bic", true}, + {"SBICKENY", "bic", true}, + {"SBICKEN1YYP", "bic", true}, + {"SBIC23NXXX", "bic", false}, + {"S23CKENXXXX", "bic", false}, + {"SBICKENXX", "bic", false}, + {"SBICKENXX9", "bic", false}, + {"SBICKEN13458", "bic", false}, + {"SBICKEN", "bic", false}, + } + + validate := New() + + for i, test := range tests { + + errs := validate.Var(test.value, test.tag) + + if test.expected { + if !IsEqual(errs, nil) { + t.Fatalf("Index: %d bic failed Error: %s", i, errs) + } + } else { + if IsEqual(errs, nil) { + t.Fatalf("Index: %d bic failed Error: %s", i, errs) + } else { + val := getError(errs, "", "") + if val.Tag() != "bic" { + t.Fatalf("Index: %d bic failed Error: %s", i, errs) + } + } + } + } + } + +func TestPostCodeByIso3166Alpha2(t *testing.T) { + tests := map[string][]struct { + value string + expected bool + }{ + "VN": { + {"ABC", false}, + {"700000", true}, + {"A1", false}, + }, + "GB": { + {"EC1A 1BB", true}, + {"CF10 1B1H", false}, + }, + "VI": { + {"00803", true}, + {"1234567", false}, + }, + "LC": { // not support regexp for post code + {"123456", false}, + }, + "XX": { // not support country + {"123456", false}, + }, + } + + validate := New() + + for cc, ccTests := range tests { + for i, test := range ccTests { + errs := validate.Var(test.value, fmt.Sprintf("postcode_iso3166_alpha2=%s", cc)) + + if test.expected { + if !IsEqual(errs, nil) { + t.Fatalf("Index: %d postcode_iso3166_alpha2=%s failed Error: %s", i, cc, errs) + } + } else { + if IsEqual(errs, nil) { + t.Fatalf("Index: %d postcode_iso3166_alpha2=%s failed Error: %s", i, cc, errs) + } + } + } + } + } + + func TestPostCodeByIso3166Alpha2Field(t *testing.T) { + tests := []struct { + Value string `validate:"postcode_iso3166_alpha2_field=CountryCode"` + CountryCode interface{} + expected bool + }{ + {"ABC", "VN", false}, + {"700000", "VN", true}, + {"A1", "VN", false}, + {"EC1A 1BB", "GB", true}, + {"CF10 1B1H", "GB", false}, + {"00803", "VI", true}, + {"1234567", "VI", false}, + {"123456", "LC", false}, // not support regexp for post code + {"123456", "XX", false}, // not support country + } + + validate := New() + + for i, test := range tests { + errs := validate.Struct(test) + if test.expected { + if !IsEqual(errs, nil) { + t.Fatalf("Index: %d postcode_iso3166_alpha2_field=CountryCode failed Error: %s", i, errs) + } + } else { + if IsEqual(errs, nil) { + t.Fatalf("Index: %d postcode_iso3166_alpha2_field=CountryCode failed Error: %s", i, errs) + } + } + } + } + + func TestPostCodeByIso3166Alpha2Field_WrongField(t *testing.T) { + type test struct { + Value string `validate:"postcode_iso3166_alpha2_field=CountryCode"` + CountryCode1 interface{} + expected bool + } + + errs := New().Struct(test{"ABC", "VN", false}) + assert.NotEqual(t, nil, errs) + } + + func TestPostCodeByIso3166Alpha2Field_MissingParam(t *testing.T) { + type test struct { + Value string `validate:"postcode_iso3166_alpha2_field="` + CountryCode1 interface{} + expected bool + } + + errs := New().Struct(test{"ABC", "VN", false}) + assert.NotEqual(t, nil, errs) + } + + func TestPostCodeByIso3166Alpha2Field_InvalidKind(t *testing.T) { + type test struct { + Value string `validate:"postcode_iso3166_alpha2_field=CountryCode"` + CountryCode interface{} + expected bool + } + defer func() { recover() }() + + _ = New().Struct(test{"ABC", 123, false}) + t.Errorf("Didn't panic as expected") + }