Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add EU countries validator #1252

Merged
merged 2 commits into from Apr 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
42 changes: 40 additions & 2 deletions baked_in.go
Expand Up @@ -64,8 +64,9 @@ var (
// defines a common or complex set of validation(s) to simplify
// adding validation to structs.
bakedInAliases = map[string]string{
"iscolor": "hexcolor|rgb|rgba|hsl|hsla",
"country_code": "iso3166_1_alpha2|iso3166_1_alpha3|iso3166_1_alpha_numeric",
"iscolor": "hexcolor|rgb|rgba|hsl|hsla",
"country_code": "iso3166_1_alpha2|iso3166_1_alpha3|iso3166_1_alpha_numeric",
"eu_country_code": "iso3166_1_alpha2_eu|iso3166_1_alpha3_eu|iso3166_1_alpha_numeric_eu",
}

// bakedInValidators is the default map of ValidationFunc
Expand Down Expand Up @@ -216,8 +217,11 @@ var (
"datetime": isDatetime,
"timezone": isTimeZone,
"iso3166_1_alpha2": isIso3166Alpha2,
"iso3166_1_alpha2_eu": isIso3166Alpha2EU,
"iso3166_1_alpha3": isIso3166Alpha3,
"iso3166_1_alpha3_eu": isIso3166Alpha3EU,
"iso3166_1_alpha_numeric": isIso3166AlphaNumeric,
"iso3166_1_alpha_numeric_eu": isIso3166AlphaNumericEU,
"iso3166_2": isIso31662,
"iso4217": isIso4217,
"iso4217_numeric": isIso4217Numeric,
Expand Down Expand Up @@ -2762,12 +2766,24 @@ func isIso3166Alpha2(fl FieldLevel) bool {
return iso3166_1_alpha2[val]
}

// isIso3166Alpha2EU is the validation function for validating if the current field's value is a valid iso3166-1 alpha-2 European Union country code.
func isIso3166Alpha2EU(fl FieldLevel) bool {
val := fl.Field().String()
return iso3166_1_alpha2_eu[val]
}

// isIso3166Alpha3 is the validation function for validating if the current field's value is a valid iso3166-1 alpha-3 country code.
func isIso3166Alpha3(fl FieldLevel) bool {
val := fl.Field().String()
return iso3166_1_alpha3[val]
}

// isIso3166Alpha3EU is the validation function for validating if the current field's value is a valid iso3166-1 alpha-3 European Union country code.
func isIso3166Alpha3EU(fl FieldLevel) bool {
val := fl.Field().String()
return iso3166_1_alpha3_eu[val]
}

// isIso3166AlphaNumeric is the validation function for validating if the current field's value is a valid iso3166-1 alpha-numeric country code.
func isIso3166AlphaNumeric(fl FieldLevel) bool {
field := fl.Field()
Expand All @@ -2790,6 +2806,28 @@ func isIso3166AlphaNumeric(fl FieldLevel) bool {
return iso3166_1_alpha_numeric[code]
}

// isIso3166AlphaNumericEU is the validation function for validating if the current field's value is a valid iso3166-1 alpha-numeric European Union country code.
func isIso3166AlphaNumericEU(fl FieldLevel) bool {
field := fl.Field()

var code int
switch field.Kind() {
case reflect.String:
i, err := strconv.Atoi(field.String())
if err != nil {
return false
}
code = i % 1000
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
code = int(field.Int() % 1000)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
code = int(field.Uint() % 1000)
default:
panic(fmt.Sprintf("Bad field type %T", field.Interface()))
}
return iso3166_1_alpha_numeric_eu[code]
}

// isIso31662 is the validation function for validating if the current field's value is a valid iso3166-2 code.
func isIso31662(fl FieldLevel) bool {
val := fl.Field().String()
Expand Down
27 changes: 27 additions & 0 deletions country_codes.go
Expand Up @@ -54,6 +54,15 @@ var iso3166_1_alpha2 = map[string]bool{
"EH": true, "YE": true, "ZM": true, "ZW": true, "XK": true,
}

var iso3166_1_alpha2_eu = map[string]bool{
"AT": true, "BE": true, "BG": true, "HR": true, "CY": true,
"CZ": true, "DK": true, "EE": true, "FI": true, "FR": true,
"DE": true, "GR": true, "HU": true, "IE": true, "IT": true,
"LV": true, "LT": true, "LU": true, "MT": true, "NL": true,
"PL": true, "PT": true, "RO": true, "SK": true, "SI": true,
"ES": true, "SE": true,
}

var iso3166_1_alpha3 = map[string]bool{
// see: https://www.iso.org/iso-3166-country-codes.html
"AFG": true, "ALB": true, "DZA": true, "ASM": true, "AND": true,
Expand Down Expand Up @@ -107,6 +116,15 @@ var iso3166_1_alpha3 = map[string]bool{
"VNM": true, "VGB": true, "VIR": true, "WLF": true, "ESH": true,
"YEM": true, "ZMB": true, "ZWE": true, "ALA": true, "UNK": true,
}

var iso3166_1_alpha3_eu = map[string]bool{
"AUT": true, "BEL": true, "BGR": true, "HRV": true, "CYP": true,
"CZE": true, "DNK": true, "EST": true, "FIN": true, "FRA": true,
"DEU": true, "GRC": true, "HUN": true, "IRL": true, "ITA": true,
"LVA": true, "LTU": true, "LUX": true, "MLT": true, "NLD": true,
"POL": true, "PRT": true, "ROU": true, "SVK": true, "SVN": true,
"ESP": true, "SWE": true,
}
var iso3166_1_alpha_numeric = map[int]bool{
// see: https://www.iso.org/iso-3166-country-codes.html
4: true, 8: true, 12: true, 16: true, 20: true,
Expand Down Expand Up @@ -161,6 +179,15 @@ var iso3166_1_alpha_numeric = map[int]bool{
887: true, 894: true, 716: true, 248: true, 153: true,
}

var iso3166_1_alpha_numeric_eu = map[int]bool{
40: true, 56: true, 100: true, 191: true, 196: true,
200: true, 208: true, 233: true, 246: true, 250: true,
276: true, 300: true, 348: true, 372: true, 380: true,
428: true, 440: true, 442: true, 470: true, 528: true,
616: true, 620: true, 642: true, 703: true, 705: true,
724: true, 752: true,
}

var iso3166_2 = map[string]bool{
"AD-02": true, "AD-03": true, "AD-04": true, "AD-05": true, "AD-06": true,
"AD-07": true, "AD-08": true, "AE-AJ": true, "AE-AZ": true, "AE-DU": true,
Expand Down
121 changes: 121 additions & 0 deletions validator_test.go
Expand Up @@ -12482,6 +12482,33 @@ func TestIsIso3166Alpha2Validation(t *testing.T) {
}
}

func TestIsIso3166Alpha2EUValidation(t *testing.T) {
tests := []struct {
value string `validate:"iso3166_1_alpha2_eu"`
expected bool
}{
{"SE", true},
{"UK", false},
}

validate := New()

for i, test := range tests {

errs := validate.Var(test.value, "iso3166_1_alpha2_eu")

if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d iso3166_1_alpha2_eu failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d iso3166_1_alpha2_eu failed Error: %s", i, errs)
}
}
}
}

func TestIsIso31662Validation(t *testing.T) {
tests := []struct {
value string `validate:"iso3166_2"`
Expand Down Expand Up @@ -12538,6 +12565,34 @@ func TestIsIso3166Alpha3Validation(t *testing.T) {
}
}

func TestIsIso3166Alpha3EUValidation(t *testing.T) {
tests := []struct {
value string `validate:"iso3166_1_alpha3_eu"`
expected bool
}{
{"POL", true},
{"SWE", true},
{"UNK", false},
}

validate := New()

for i, test := range tests {

errs := validate.Var(test.value, "iso3166_1_alpha3_eu")

if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d iso3166_1_alpha3_eu failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d iso3166_1_alpha3_eu failed Error: %s", i, errs)
}
}
}
}

func TestIsIso3166AlphaNumericValidation(t *testing.T) {
tests := []struct {
value interface{}
Expand Down Expand Up @@ -12573,6 +12628,39 @@ func TestIsIso3166AlphaNumericValidation(t *testing.T) {
}, "Bad field type []string")
}

func TestIsIso3166AlphaNumericEUValidation(t *testing.T) {
tests := []struct {
value interface{}
expected bool
}{
{752, true}, //Sweden
{"752", true},
{826, false}, // UK
{"826", false},
}

validate := New()

for i, test := range tests {

errs := validate.Var(test.value, "iso3166_1_alpha_numeric_eu")

if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d iso3166_1_alpha_numeric_eu failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d iso3166_1_alpha_numeric_eu failed Error: %s", i, errs)
}
}
}

PanicMatches(t, func() {
_ = validate.Var([]string{"1"}, "iso3166_1_alpha_numeric_eu")
}, "Bad field type []string")
}

func TestCountryCodeValidation(t *testing.T) {
tests := []struct {
value interface{}
Expand Down Expand Up @@ -12606,6 +12694,39 @@ func TestCountryCodeValidation(t *testing.T) {
}
}

func TestEUCountryCodeValidation(t *testing.T) {
tests := []struct {
value interface{}
expected bool
}{
{724, true},
{0, false},
{1, false},
{"POL", true},
{"NO", false},
{"724", true},
{"1", false},
{"0", false},
}

validate := New()

for i, test := range tests {

errs := validate.Var(test.value, "eu_country_code")

if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d eu_country_code failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d eu_country_code failed Error: %s", i, errs)
}
}
}
}

func TestIsIso4217Validation(t *testing.T) {
tests := []struct {
value string `validate:"iso4217"`
Expand Down