Skip to content

Commit

Permalink
Add cron support (#1045)
Browse files Browse the repository at this point in the history
  • Loading branch information
albertoforcato committed Mar 19, 2023
1 parent 89b91ce commit 3ee65f8
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 2 deletions.
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -155,6 +155,7 @@ Baked-in Validations
| btc_addr | Bitcoin Address |
| btc_addr_bech32 | Bitcoin Bech32 Address (segwit) |
| credit_card | Credit Card Number |
| cron | Cron |
| datetime | Datetime |
| e164 | e164 formatted phone number |
| email | E-mail String
Expand Down
7 changes: 7 additions & 0 deletions baked_in.go
Expand Up @@ -218,6 +218,7 @@ var (
"semver": isSemverFormat,
"dns_rfc1035_label": isDnsRFC1035LabelFormat,
"credit_card": isCreditCard,
"cron": isCron,
}
)

Expand Down Expand Up @@ -2579,3 +2580,9 @@ func isCreditCard(fl FieldLevel) bool {
}
return (sum % 10) == 0
}

// isCron is the validation function for validating if the current field's value is a valid cron expression
func isCron(fl FieldLevel) bool {
cronString := fl.Field().String()
return cronRegex.MatchString(cronString)
}
6 changes: 6 additions & 0 deletions doc.go
Expand Up @@ -1323,6 +1323,12 @@ This validates that a string value contains a valid credit card number using Luh
Usage: credit_card
Cron
This validates that a string value contains a valid cron expression.
Usage: cron
Alias Validators and Tags
NOTE: When returning an error, the tag returned in "FieldError" will be
Expand Down
2 changes: 2 additions & 0 deletions regexes.go
Expand Up @@ -64,6 +64,7 @@ const (
bicRegexString = `^[A-Za-z]{6}[A-Za-z0-9]{2}([A-Za-z0-9]{3})?$`
semverRegexString = `^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$` // numbered capture groups https://semver.org/
dnsRegexStringRFC1035Label = "^[a-z]([-a-z0-9]*[a-z0-9]){0,62}$"
cronRegexString = `(@(annually|yearly|monthly|weekly|daily|hourly|reboot))|(@every (\d+(ns|us|µs|ms|s|m|h))+)|((((\d+,)+\d+|(\d+(\/|-)\d+)|\d+|\*) ?){5,7})`
)

var (
Expand Down Expand Up @@ -126,4 +127,5 @@ var (
bicRegex = regexp.MustCompile(bicRegexString)
semverRegex = regexp.MustCompile(semverRegexString)
dnsRegexRFC1035Label = regexp.MustCompile(dnsRegexStringRFC1035Label)
cronRegex = regexp.MustCompile(cronRegexString)
)
5 changes: 5 additions & 0 deletions translations/en/en.go
Expand Up @@ -1281,6 +1281,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} must be a valid color",
override: false,
},
{
tag: "cron",
translation: "{0} must be a valid cron expression",
override: false,
},
{
tag: "oneof",
translation: "{0} must be one of [{1}]",
Expand Down
9 changes: 7 additions & 2 deletions translations/it/it.go
Expand Up @@ -124,7 +124,7 @@ 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} deve essere lungo almeno {1}", false); err != nil {
return
}
Expand Down Expand Up @@ -432,7 +432,7 @@ 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} deve essere lungo al massimo {1}", false); err != nil {
return
}
Expand Down Expand Up @@ -1132,6 +1132,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} deve essere un colore valido",
override: false,
},
{
tag: "cron",
translation: "{0} deve essere una stringa cron valida",
override: false,
},
{
tag: "oneof",
translation: "{0} deve essere uno di [{1}]",
Expand Down
34 changes: 34 additions & 0 deletions validator_test.go
Expand Up @@ -12524,3 +12524,37 @@ func TestMultiOrOperatorGroup(t *testing.T) {
}
}
}

func TestCronExpressionValidation(t *testing.T) {
tests := []struct {
value string `validate:"cron"`
tag string
expected bool
}{
{"0 0 12 * * ?", "cron", true},
{"0 15 10 ? * *", "cron", true},
{"0 15 10 * * ?", "cron", true},
{"0 15 10 * * ? 2005", "cron", true},
{"0 15 10 ? * 6L", "cron", true},
{"0 15 10 ? * 6L 2002-2005", "cron", true},
{"*/20 * * * *", "cron", true},
{"0 15 10 ? * MON-FRI", "cron", true},
{"0 15 10 ? * 6#3", "cron", true},
{"wrong", "cron", 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 cron "%s" failed Error: %s`, i, test.value, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf(`Index: %d cron "%s" should have errs`, i, test.value)
}
}
}
}

0 comments on commit 3ee65f8

Please sign in to comment.