commit
3851e40370
|
@ -45,7 +45,7 @@ handle query_nowhitespace_nodash => sub {
|
|||
# Tracking number.
|
||||
my $package_number = '';
|
||||
|
||||
# Exclsuive trigger.
|
||||
# Exclusive trigger.
|
||||
if ($1 || $2) {
|
||||
$package_number = $1 || $2;
|
||||
$is_capost = 2;
|
||||
|
|
|
@ -1,16 +1,25 @@
|
|||
package DDG::Goodie::ParseCron;
|
||||
# ABSTRACT: Parsing Crontabs - Show next occurence of cron event in human-readable form.
|
||||
# ABSTRACT: Parsing Crontabs - Show cron events in human-readable form.
|
||||
# Example input:
|
||||
# crontab 42 12 3 Feb Sat
|
||||
# Example output:
|
||||
# Event will start next at 12:42:00 on 2 Feb, 2013
|
||||
# at 12:42pm on the 3rd and on Saturday in February
|
||||
#
|
||||
|
||||
use DDG::Goodie;
|
||||
use Schedule::Cron::Events;
|
||||
|
||||
my @mon = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
|
||||
my @day = qw(Mon Tue Wed Thu Fri Sat Sun);
|
||||
use strict;
|
||||
use warnings;
|
||||
use Try::Tiny;
|
||||
|
||||
my @month_names = qw(January February March April May June
|
||||
July August September October November December);
|
||||
my @weekday_names = qw(Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday);
|
||||
|
||||
my (%month_short_names, %weekday_short_names);
|
||||
|
||||
@month_short_names{map substr(lc($_), 0, 3), @month_names} = (1..12);
|
||||
@weekday_short_names{map substr(lc($_), 0, 3), @weekday_names} = (0..7);
|
||||
|
||||
triggers start => 'crontab', 'cron', 'cronjob';
|
||||
|
||||
|
@ -23,28 +32,261 @@ name 'ParseCron';
|
|||
code_url 'https://github.com/duckduckgo/zeroclickinfo-goodies/blob/master/lib/DDG/Goodie/ParseCron.pm';
|
||||
category 'computing_info';
|
||||
topics 'sysadmin';
|
||||
attribution web => ['http://indeliblestamp.com', 'Arun S'],
|
||||
github => ['indeliblestamp', 'Arun S'];
|
||||
attribution github => [ 'https://github.com/W25', 'W25' ] ;
|
||||
|
||||
# Get ordinal (for days)
|
||||
sub get_ordinal {
|
||||
my $num = shift;
|
||||
return $num . 'th' if 11 <= $num % 100 && $num % 100 <= 13;
|
||||
return $num . 'rd' if $num % 10 == 3;
|
||||
return $num . 'nd' if $num % 10 == 2;
|
||||
return $num . 'st' if $num % 10 == 1;
|
||||
return $num . 'th';
|
||||
}
|
||||
|
||||
# Get frequency ("every X hours" or "every other day")
|
||||
sub get_freq {
|
||||
my ($freq, $singular, $plural) = @_;
|
||||
return "every $singular" if $freq == 1;
|
||||
return $freq == 2 ? "every other $singular" : "every $freq $plural";
|
||||
}
|
||||
|
||||
# Join the array with commas and "and"
|
||||
sub join_list {
|
||||
my $last = pop @_;
|
||||
return $last if @_ == 0; # one item
|
||||
|
||||
my $out = join(', ', @_);
|
||||
$out .= ',' if @_ > 1; # three or more items; add a comma before "and"
|
||||
return "$out and $last";
|
||||
}
|
||||
|
||||
# Should it be repeated every day/month/hour/minute
|
||||
sub is_every {
|
||||
my $field = shift;
|
||||
return $field eq '*' || $field eq '*/1';
|
||||
}
|
||||
|
||||
sub check_bounds {
|
||||
my ($value, $min, $max, $name) = @_;
|
||||
die "Invalid $name $value\n" if $value < $min || $value > $max;
|
||||
}
|
||||
|
||||
# Replace a name ("Jan", "Feb", "Sat", "Sun") with the corresponding index
|
||||
sub replace_names {
|
||||
my ($value, $singular, $names) = @_;
|
||||
|
||||
# It's not a month or a day of week, but a name is provided
|
||||
die "Invalid $singular $value\n" if !defined($names) && $value =~ /[a-z]{3}/i;
|
||||
|
||||
# It's a number, no need to search for a name
|
||||
return $value if $value !~ /[a-z]{3}/i;
|
||||
|
||||
# Name not found
|
||||
die "Invalid $singular $value\n" unless exists $names->{lc($value)};
|
||||
|
||||
return $names->{lc($value)};
|
||||
}
|
||||
|
||||
# Parse a field (minute, hour, day, month, or weekday), call format_value for each value, and compose a string
|
||||
sub parse_field {
|
||||
my ($field, $singular, $plural, $min, $max, $format_value, $names) = @_;
|
||||
|
||||
# "every X days" ("*/X" or just "*")
|
||||
if ($field =~ m!^\*(?:/(\d+))?$!) {
|
||||
check_bounds($1, 1, $max, $singular) if defined $1;
|
||||
return get_freq(defined $1 ? $1 : 1, $singular, $plural);
|
||||
}
|
||||
|
||||
my @components = ();
|
||||
my $i = 0;
|
||||
|
||||
for (split ',', $field) {
|
||||
die "Invalid $singular $_\n" unless $_ =~ m!^(\d+|[a-z]{3})(?:-(\d+|[a-z]{3})(?:/(\d+))?)?$!i;
|
||||
my ($start, $stop, $freq) = ($1, $2, $3);
|
||||
$start = replace_names($start, $singular, $names);
|
||||
$stop = replace_names($stop, $singular, $names) if defined $stop;
|
||||
|
||||
my $res = '';
|
||||
if (defined $freq) {
|
||||
check_bounds($freq, 1, $max, $singular);
|
||||
$res .= get_freq($freq, $singular, $plural) . ' ';
|
||||
}
|
||||
if (defined $stop) { # a range (from X to Y)
|
||||
check_bounds($start, $min, $max, $singular);
|
||||
check_bounds($stop, $min, $max, $singular);
|
||||
|
||||
if ($singular eq 'month' || $singular eq 'day of the week') {
|
||||
$res .= &$format_value($start, "start/$i") . ' through ' . &$format_value($stop, "stop/$i");
|
||||
} else {
|
||||
$res .= 'from ' . &$format_value($start, "start/$i") . ' to ' . &$format_value($stop, "stop/$i");
|
||||
}
|
||||
} else {
|
||||
check_bounds($start, $min, $max, $singular);
|
||||
$res .= &$format_value($start, "single/$i");
|
||||
}
|
||||
$i++;
|
||||
push @components, $res;
|
||||
}
|
||||
return join_list(@components);
|
||||
}
|
||||
|
||||
# An alternative parser that returns an array of all possible values
|
||||
sub get_all_values {
|
||||
my ($field, $singular, $min, $max) = @_;
|
||||
|
||||
my @components = split ',', $field;
|
||||
|
||||
if ($field =~ m!^\*(?:/(\d+))?$!) { # "every X days" ("*/X" or just "*")
|
||||
if (defined $1) {
|
||||
check_bounds($1, 1, $max, $singular);
|
||||
return map {$_ * $1 + $min} 0 .. (($max - $min) / $1);
|
||||
}
|
||||
return $min..$max;
|
||||
}
|
||||
|
||||
my @values = ();
|
||||
|
||||
for (@components) {
|
||||
die "Invalid $singular $_\n" unless $_ =~ m!^(\d+)(?:-(\d+)(?:/(\d+))?)?$!;
|
||||
|
||||
check_bounds($3, 1, $max, $singular) if defined $3;
|
||||
check_bounds($2, $min, $max, $singular) if defined $2;
|
||||
check_bounds($1, $min, $max, $singular) if defined $1;
|
||||
|
||||
if (defined $3) { # a range of values with frequency
|
||||
push @values, map {$_ * $3 + $1} 0 .. (($2 - $1) / $3);
|
||||
} elsif (defined $2) {
|
||||
push @values, $1..$2; # a range of values
|
||||
} else {
|
||||
push @values, $1;
|
||||
}
|
||||
}
|
||||
|
||||
@values = sort {$a <=> $b} @values;
|
||||
|
||||
# Remove duplicates
|
||||
my %seen;
|
||||
return grep {!$seen{$_}++} @values;
|
||||
}
|
||||
|
||||
# Calculate the cartesian product of all possible hours and minutes, if it's not too big
|
||||
sub get_simple_time {
|
||||
my ($minute, $hour) = @_;
|
||||
|
||||
my @hours = get_all_values($hour, 'hour', 0, 23);
|
||||
my @minutes = get_all_values($minute, 'minute', 0, 59);
|
||||
|
||||
return if (scalar(@hours) * scalar(@minutes) > 10); # It's too big
|
||||
|
||||
my @times = ();
|
||||
for my $hour (@hours) {
|
||||
push @times, map {sprintf('%d:%02d%s', $hour % 12 == 0 ? 12 : $hour % 12,
|
||||
$_, $hour < 12 ? 'am' : 'pm')} @minutes;
|
||||
}
|
||||
return 'at ' . join_list(@times);
|
||||
}
|
||||
|
||||
# Parse minute and hour (the first two fields)
|
||||
sub parse_time {
|
||||
my ($minute, $hour) = @_;
|
||||
|
||||
# Particular cases
|
||||
return 'at midnight' if $minute eq '0' && $hour eq '0';
|
||||
|
||||
my $out = get_simple_time($minute, $hour);
|
||||
return $out if defined $out;
|
||||
|
||||
# The common case
|
||||
$out = '';
|
||||
|
||||
# Parse minutes
|
||||
if ($minute =~ /^\d+(?:,\d+)*$/ && $minute ne '0') { # a simple comma-separated list
|
||||
my @components = split ',', $minute;
|
||||
for (@components) {
|
||||
check_bounds($_, 0, 59, 'minute');
|
||||
}
|
||||
$out .= join_list(@components) . ' ' . ($components[-1] == 1 ? 'minute' : 'minutes') . ' after '
|
||||
} elsif ($minute ne '0') {
|
||||
$out .= parse_field($minute, 'minute', 'minutes', 0, 59, sub {
|
||||
return $_[0] if $_[1] =~ /^start/;
|
||||
return $_[0] == 1 ? 'a minute' : "$_[0] minutes";
|
||||
});
|
||||
# Insert the right preposition
|
||||
if ($minute =~ m!^\*(?:/\d+)?$!) { # every X minutes
|
||||
return $out if is_every($hour);
|
||||
$out .= ' of ';
|
||||
} else {
|
||||
$out .= ' after ';
|
||||
}
|
||||
}
|
||||
|
||||
# Parse hours
|
||||
$out .= parse_field($hour, 'hour', 'hours', 0, 23, sub {
|
||||
return ($_[0] % 12 == 0 ? 12 : $_[0] % 12) . ($_[0] < 12 ? 'am' : 'pm');
|
||||
});
|
||||
return $out;
|
||||
}
|
||||
|
||||
# Parse day, month, and weekday
|
||||
sub parse_date {
|
||||
my ($day, $month, $weekday) = @_;
|
||||
|
||||
return 'every day' if (is_every($day) && is_every($month) && is_every($weekday));
|
||||
|
||||
my $dayres = parse_field($day, 'day', 'days', 1, 31, sub {
|
||||
return 'on the ' . get_ordinal($_[0]) if $_[1] eq 'single/0'; # insert the preposition for the first single value
|
||||
return get_ordinal($_[0]);
|
||||
});
|
||||
|
||||
my $monthres = parse_field($month, 'month', 'months', 1, 12, sub {
|
||||
return $month_names[$_[0] - 1];
|
||||
}, \%month_short_names);
|
||||
|
||||
if (is_every($weekday)) { # No weekday is specified
|
||||
return $dayres if is_every($month) && $day =~ m!^\*/\d+$!; # every X days
|
||||
return "$dayres of $monthres";
|
||||
}
|
||||
|
||||
my $weekres = parse_field($weekday, 'day of the week', 'days of the week', 0, 7, sub {
|
||||
return 'on ' . $weekday_names[$_[0]] if $_[1] eq 'single/0';
|
||||
return $weekday_names[$_[0]];
|
||||
}, \%weekday_short_names);
|
||||
|
||||
return "$weekres" . (is_every($month) ? '' : " in $monthres") if is_every($day);
|
||||
|
||||
# Both day of week and day of month are specified
|
||||
return "$dayres and $weekres" . (is_every($month) ? '' : " in $monthres");
|
||||
}
|
||||
|
||||
# The main function
|
||||
handle remainder => sub {
|
||||
my $crontab = $_;
|
||||
# We replace Jan,Feb.. and Mon,Tue.. with 1,2..
|
||||
foreach (0..$#mon) {
|
||||
my $newmonth=$_+1;
|
||||
$crontab =~ s/$mon[$_]/$newmonth/;
|
||||
my $line = shift;
|
||||
|
||||
my ($minute, $hour, $day, $month, $weekday) = split(' ', $line);
|
||||
|
||||
return if (!defined $weekday); # less than five fields
|
||||
|
||||
try {
|
||||
my $time = parse_time($minute, $hour);
|
||||
my $date = parse_date($day, $month, $weekday);
|
||||
|
||||
# If it's something like "every two hours", don't add "every day"
|
||||
$time .= ' ' . $date unless $time =~ /^every / && $date eq 'every day';
|
||||
|
||||
return $time, structured_answer => {
|
||||
input => [$line],
|
||||
operation => 'Crontab',
|
||||
result => $time
|
||||
};
|
||||
} catch {
|
||||
chomp;
|
||||
return $_, structured_answer => {
|
||||
input => [$line],
|
||||
operation => 'Crontab',
|
||||
result => $_
|
||||
};
|
||||
}
|
||||
foreach (0..$#day) {
|
||||
my $newday=$_+1;
|
||||
$crontab =~ s/$day[$_]/$newday/;
|
||||
}
|
||||
my $cron = Schedule::Cron::Events->new($crontab) or return;
|
||||
my $text;
|
||||
# Fix for issue #95: Show the next 3 events instead of just one.
|
||||
for (my $count=1;$count<=3;$count++) {
|
||||
my ($sec, $min, $hour, $day, $month, $year) = $cron->nextEvent;
|
||||
$text .= sprintf("%2d:%02d:%02d on %d %s, %d\n", $hour, $min, $sec, $day, $mon[$month], ($year+1900));
|
||||
}
|
||||
return "Cron will schedule the job at this frequency: \n$text" if $_;
|
||||
return;
|
||||
|
||||
};
|
||||
1;
|
||||
|
|
338
t/ParseCron.t
338
t/ParseCron.t
|
@ -12,10 +12,340 @@ ddg_goodie_test(
|
|||
[qw(
|
||||
DDG::Goodie::ParseCron
|
||||
)],
|
||||
'crontab * */3 * * *' => test_zci(qr/^Cron will schedule the job at this frequency:\s*\n\s*\d{1,2}:\d{1,2}:\d{1,2} on \d{1,2} [a-zA-Z]{3}, \d{4}\s*\n\s*\d{1,2}:\d{1,2}:\d{1,2} on \d{1,2} [a-zA-Z]{3}, \d{4}\s*\n\s*\d{1,2}:\d{1,2}:\d{1,2} on \d{1,2} [a-zA-Z]{3}, \d{4}$/),
|
||||
'crontab 42 12 3 Feb Sat' => test_zci(qr/^Cron will schedule the job at this frequency:\s*\n\s*\d{1,2}:\d{1,2}:\d{1,2} on \d{1,2} [a-zA-Z]{3}, \d{4}\s*\n\s*\d{1,2}:\d{1,2}:\d{1,2} on \d{1,2} [a-zA-Z]{3}, \d{4}\s*\n\s*\d{1,2}:\d{1,2}:\d{1,2} on \d{1,2} [a-zA-Z]{3}, \d{4}$/),
|
||||
# Time
|
||||
'cron * * * * *' => test_zci('every minute',
|
||||
structured_answer => {
|
||||
input => ['* * * * *'],
|
||||
operation => 'Crontab',
|
||||
result => 'every minute'
|
||||
}),
|
||||
'cron 5 0 * * *' => test_zci('at 12:05am every day',
|
||||
structured_answer => {
|
||||
input => ['5 0 * * *'],
|
||||
operation => 'Crontab',
|
||||
result => 'at 12:05am every day'
|
||||
}),
|
||||
'cron 0 */2 * * *' => test_zci('every other hour',
|
||||
structured_answer => {
|
||||
input => ['0 */2 * * *'],
|
||||
operation => 'Crontab',
|
||||
result => 'every other hour'
|
||||
}),
|
||||
'cron 0 0-23/2 * * *' => test_zci('every other hour from 12am to 11pm',
|
||||
structured_answer => {
|
||||
input => ['0 0-23/2 * * *'],
|
||||
operation => 'Crontab',
|
||||
result => 'every other hour from 12am to 11pm'
|
||||
}),
|
||||
'cron 15 0-23/2,10,14 * * *' => test_zci('15 minutes after every other hour from 12am to 11pm, 10am, and 2pm every day',
|
||||
structured_answer => {
|
||||
input => ['15 0-23/2,10,14 * * *'],
|
||||
operation => 'Crontab',
|
||||
result => '15 minutes after every other hour from 12am to 11pm, 10am, and 2pm every day'
|
||||
}),
|
||||
'cron 0,15,30,45 4 * * *' => test_zci('at 4:00am, 4:15am, 4:30am, and 4:45am every day',
|
||||
structured_answer => {
|
||||
input => ['0,15,30,45 4 * * *'],
|
||||
operation => 'Crontab',
|
||||
result => 'at 4:00am, 4:15am, 4:30am, and 4:45am every day'
|
||||
}), # exact times are returned
|
||||
'cron 45,15,30,15,0 4 * * *' => test_zci('at 4:00am, 4:15am, 4:30am, and 4:45am every day',
|
||||
structured_answer => {
|
||||
input => ['45,15,30,15,0 4 * * *'],
|
||||
operation => 'Crontab',
|
||||
result => 'at 4:00am, 4:15am, 4:30am, and 4:45am every day'
|
||||
}),
|
||||
'cron 0,15,30,45 4,6,7,8 * * *' => test_zci('0, 15, 30, and 45 minutes after 4am, 6am, 7am, and 8am every day',
|
||||
structured_answer => {
|
||||
input => ['0,15,30,45 4,6,7,8 * * *'],
|
||||
operation => 'Crontab',
|
||||
result => '0, 15, 30, and 45 minutes after 4am, 6am, 7am, and 8am every day'
|
||||
}), # too many exact times
|
||||
'cron 45,15,30,15,0 4,6,7,8 * * *' => test_zci('45, 15, 30, 15, and 0 minutes after 4am, 6am, 7am, and 8am every day',
|
||||
structured_answer => {
|
||||
input => ['45,15,30,15,0 4,6,7,8 * * *'],
|
||||
operation => 'Crontab',
|
||||
result => '45, 15, 30, 15, and 0 minutes after 4am, 6am, 7am, and 8am every day'
|
||||
}),
|
||||
'cron 5 1,4,6-7 * * *' => test_zci('at 1:05am, 4:05am, 6:05am, and 7:05am every day',
|
||||
structured_answer => {
|
||||
input => ['5 1,4,6-7 * * *'],
|
||||
operation => 'Crontab',
|
||||
result => 'at 1:05am, 4:05am, 6:05am, and 7:05am every day'
|
||||
}),
|
||||
'cron 5 13,5 * * *' => test_zci('at 5:05am and 1:05pm every day',
|
||||
structured_answer => {
|
||||
input => ['5 13,5 * * *'],
|
||||
operation => 'Crontab',
|
||||
result => 'at 5:05am and 1:05pm every day'
|
||||
}),
|
||||
'cron 1-9/2 * * * *' => test_zci('every other minute from 1 to 9 minutes after every hour',
|
||||
structured_answer => {
|
||||
input => ['1-9/2 * * * *'],
|
||||
operation => 'Crontab',
|
||||
result => 'every other minute from 1 to 9 minutes after every hour'
|
||||
}),
|
||||
'cron */5 4 * * *' => test_zci('every 5 minutes of 4am',
|
||||
structured_answer => {
|
||||
input => ['*/5 4 * * *'],
|
||||
operation => 'Crontab',
|
||||
result => 'every 5 minutes of 4am'
|
||||
}),
|
||||
'cron */5 * * * *' => test_zci('every 5 minutes',
|
||||
structured_answer => {
|
||||
input => ['*/5 * * * *'],
|
||||
operation => 'Crontab',
|
||||
result => 'every 5 minutes'
|
||||
}),
|
||||
'crontab * */3 * * *' => test_zci('every minute of every 3 hours',
|
||||
structured_answer => {
|
||||
input => ['* */3 * * *'],
|
||||
operation => 'Crontab',
|
||||
result => 'every minute of every 3 hours'
|
||||
}),
|
||||
|
||||
# Dates
|
||||
'cron 0 9 */3 * *' => test_zci('at 9:00am every 3 days',
|
||||
structured_answer => {
|
||||
input => ['0 9 */3 * *'],
|
||||
operation => 'Crontab',
|
||||
result => 'at 9:00am every 3 days'
|
||||
}),
|
||||
'cron 0 9 */1 * *' => test_zci('at 9:00am every day',
|
||||
structured_answer => {
|
||||
input => ['0 9 */1 * *'],
|
||||
operation => 'Crontab',
|
||||
result => 'at 9:00am every day'
|
||||
}),
|
||||
'cron 0 9 1-15/2 * *' => test_zci('at 9:00am every other day from 1st to 15th of every month',
|
||||
structured_answer => {
|
||||
input => ['0 9 1-15/2 * *'],
|
||||
operation => 'Crontab',
|
||||
result => 'at 9:00am every other day from 1st to 15th of every month'
|
||||
}),
|
||||
'cron 0 9 * 6-8 *' => test_zci('at 9:00am every day of June through August',
|
||||
structured_answer => {
|
||||
input => ['0 9 * 6-8 *'],
|
||||
operation => 'Crontab',
|
||||
result => 'at 9:00am every day of June through August'
|
||||
}),
|
||||
'cron 0 9 */5 6-8 *' => test_zci('at 9:00am every 5 days of June through August',
|
||||
structured_answer => {
|
||||
input => ['0 9 */5 6-8 *'],
|
||||
operation => 'Crontab',
|
||||
result => 'at 9:00am every 5 days of June through August'
|
||||
}),
|
||||
'cron 0 12 * */2 *' => test_zci('at 12:00pm every day of every other month',
|
||||
structured_answer => {
|
||||
input => ['0 12 * */2 *'],
|
||||
operation => 'Crontab',
|
||||
result => 'at 12:00pm every day of every other month'
|
||||
}),
|
||||
'cron 0 12 * * */2' => test_zci('at 12:00pm every other day of the week',
|
||||
structured_answer => {
|
||||
input => ['0 12 * * */2'],
|
||||
operation => 'Crontab',
|
||||
result => 'at 12:00pm every other day of the week'
|
||||
}),
|
||||
'cron 0 0 23 * *' => test_zci('at midnight on the 23rd of every month',
|
||||
structured_answer => {
|
||||
input => ['0 0 23 * *'],
|
||||
operation => 'Crontab',
|
||||
result => 'at midnight on the 23rd of every month'
|
||||
}), # test ordinal suffixes
|
||||
'cron 0 0 13 * *' => test_zci('at midnight on the 13th of every month',
|
||||
structured_answer => {
|
||||
input => ['0 0 13 * *'],
|
||||
operation => 'Crontab',
|
||||
result => 'at midnight on the 13th of every month'
|
||||
}),
|
||||
'cron 0 0 22 * *' => test_zci('at midnight on the 22nd of every month',
|
||||
structured_answer => {
|
||||
input => ['0 0 22 * *'],
|
||||
operation => 'Crontab',
|
||||
result => 'at midnight on the 22nd of every month'
|
||||
}),
|
||||
'cron 0 0 21 * *' => test_zci('at midnight on the 21st of every month',
|
||||
structured_answer => {
|
||||
input => ['0 0 21 * *'],
|
||||
operation => 'Crontab',
|
||||
result => 'at midnight on the 21st of every month'
|
||||
}),
|
||||
'cron 0 0 20 * *' => test_zci('at midnight on the 20th of every month',
|
||||
structured_answer => {
|
||||
input => ['0 0 20 * *'],
|
||||
operation => 'Crontab',
|
||||
result => 'at midnight on the 20th of every month'
|
||||
}),
|
||||
'cron 0 0 1,14 1-11 *' => test_zci('at midnight on the 1st and 14th of January through November',
|
||||
structured_answer => {
|
||||
input => ['0 0 1,14 1-11 *'],
|
||||
operation => 'Crontab',
|
||||
result => 'at midnight on the 1st and 14th of January through November'
|
||||
}),
|
||||
'cron 0 0 * * 1-5' => test_zci('at midnight Monday through Friday',
|
||||
structured_answer => {
|
||||
input => ['0 0 * * 1-5'],
|
||||
operation => 'Crontab',
|
||||
result => 'at midnight Monday through Friday'
|
||||
}),
|
||||
'cron 0 0 * 12 1-5' => test_zci('at midnight Monday through Friday in December',
|
||||
structured_answer => {
|
||||
input => ['0 0 * 12 1-5'],
|
||||
operation => 'Crontab',
|
||||
result => 'at midnight Monday through Friday in December'
|
||||
}),
|
||||
'cron 0 0 23 * 1-5' => test_zci('at midnight on the 23rd and Monday through Friday',
|
||||
structured_answer => {
|
||||
input => ['0 0 23 * 1-5'],
|
||||
operation => 'Crontab',
|
||||
result => 'at midnight on the 23rd and Monday through Friday'
|
||||
}),
|
||||
'cron 0 0 23 1 1-5' => test_zci('at midnight on the 23rd and Monday through Friday in January',
|
||||
structured_answer => {
|
||||
input => ['0 0 23 1 1-5'],
|
||||
operation => 'Crontab',
|
||||
result => 'at midnight on the 23rd and Monday through Friday in January'
|
||||
}),
|
||||
'cron 0 0 * * 1-5' => test_zci('at midnight Monday through Friday',
|
||||
structured_answer => {
|
||||
input => ['0 0 * * 1-5'],
|
||||
operation => 'Crontab',
|
||||
result => 'at midnight Monday through Friday'
|
||||
}),
|
||||
'cron 0 0 * * Sat-Sun' => test_zci('at midnight Saturday through Sunday',
|
||||
structured_answer => {
|
||||
input => ['0 0 * * Sat-Sun'],
|
||||
operation => 'Crontab',
|
||||
result => 'at midnight Saturday through Sunday'
|
||||
}),
|
||||
'cron 0 0 * DEC,Jan-feb Sat-Sun' => test_zci('at midnight Saturday through Sunday in December and January through February',
|
||||
structured_answer => {
|
||||
input => ['0 0 * DEC,Jan-feb Sat-Sun'],
|
||||
operation => 'Crontab',
|
||||
result => 'at midnight Saturday through Sunday in December and January through February'
|
||||
}),
|
||||
'cron 0 0 * * 0' => test_zci('at midnight on Sunday',
|
||||
structured_answer => {
|
||||
input => ['0 0 * * 0'],
|
||||
operation => 'Crontab',
|
||||
result => 'at midnight on Sunday'
|
||||
}),
|
||||
'cron 0 0 * * 7' => test_zci('at midnight on Sunday',
|
||||
structured_answer => {
|
||||
input => ['0 0 * * 7'],
|
||||
operation => 'Crontab',
|
||||
result => 'at midnight on Sunday'
|
||||
}),
|
||||
|
||||
# Syntax errors
|
||||
'cron 0 0 * *' => undef,
|
||||
'cron 0 0 *' => undef,
|
||||
'cron 0 0' => undef,
|
||||
'cron 0' => undef,
|
||||
'cron ' => undef,
|
||||
'cron help' => undef,
|
||||
'cron cheatsheet' => undef,
|
||||
'crontab examples' => undef,
|
||||
|
||||
'cron 96 4 * * *' => test_zci('Invalid minute 96',
|
||||
structured_answer => {
|
||||
input => ['96 4 * * *'],
|
||||
operation => 'Crontab',
|
||||
result => 'Invalid minute 96'
|
||||
}),
|
||||
'cron 6 45 * * *' => test_zci('Invalid hour 45',
|
||||
structured_answer => {
|
||||
input => ['6 45 * * *'],
|
||||
operation => 'Crontab',
|
||||
result => 'Invalid hour 45'
|
||||
}),
|
||||
'cron 15,1-93 5 * * *' => test_zci('Invalid minute 93',
|
||||
structured_answer => {
|
||||
input => ['15,1-93 5 * * *'],
|
||||
operation => 'Crontab',
|
||||
result => 'Invalid minute 93'
|
||||
}),
|
||||
'cron 15,93-7 5 * * *' => test_zci('Invalid minute 93',
|
||||
structured_answer => {
|
||||
input => ['15,93-7 5 * * *'],
|
||||
operation => 'Crontab',
|
||||
result => 'Invalid minute 93'
|
||||
}),
|
||||
'cron 1 50,16 * * *' => test_zci('Invalid hour 50',
|
||||
structured_answer => {
|
||||
input => ['1 50,16 * * *'],
|
||||
operation => 'Crontab',
|
||||
result => 'Invalid hour 50'
|
||||
}),
|
||||
'cron 0 0 32 * *' => test_zci('Invalid day 32',
|
||||
structured_answer => {
|
||||
input => ['0 0 32 * *'],
|
||||
operation => 'Crontab',
|
||||
result => 'Invalid day 32'
|
||||
}),
|
||||
'cron 0 0 0 * *' => test_zci('Invalid day 0',
|
||||
structured_answer => {
|
||||
input => ['0 0 0 * *'],
|
||||
operation => 'Crontab',
|
||||
result => 'Invalid day 0'
|
||||
}),
|
||||
'cron 0 0 2 0 *' => test_zci('Invalid month 0',
|
||||
structured_answer => {
|
||||
input => ['0 0 2 0 *'],
|
||||
operation => 'Crontab',
|
||||
result => 'Invalid month 0'
|
||||
}),
|
||||
'cron 0 0 * * 8' => test_zci('Invalid day of the week 8',
|
||||
structured_answer => {
|
||||
input => ['0 0 * * 8'],
|
||||
operation => 'Crontab',
|
||||
result => 'Invalid day of the week 8'
|
||||
}),
|
||||
'cron 0 0 * * -1' => test_zci('Invalid day of the week -1',
|
||||
structured_answer => {
|
||||
input => ['0 0 * * -1'],
|
||||
operation => 'Crontab',
|
||||
result => 'Invalid day of the week -1'
|
||||
}),
|
||||
'cron 0 0 * ABC *' => test_zci('Invalid month ABC',
|
||||
structured_answer => {
|
||||
input => ['0 0 * ABC *'],
|
||||
operation => 'Crontab',
|
||||
result => 'Invalid month ABC'
|
||||
}),
|
||||
'cron 0 0 ABC * *' => test_zci('Invalid day ABC',
|
||||
structured_answer => {
|
||||
input => ['0 0 ABC * *'],
|
||||
operation => 'Crontab',
|
||||
result => 'Invalid day ABC'
|
||||
}),
|
||||
'cron ! * * * *' => test_zci('Invalid minute !',
|
||||
structured_answer => {
|
||||
input => ['! * * * *'],
|
||||
operation => 'Crontab',
|
||||
result => 'Invalid minute !'
|
||||
}),
|
||||
'cron 0 9 */90 * *' => test_zci('Invalid day 90',
|
||||
structured_answer => {
|
||||
input => ['0 9 */90 * *'],
|
||||
operation => 'Crontab',
|
||||
result => 'Invalid day 90'
|
||||
}),
|
||||
'cron 0 9 */0 * *' => test_zci('Invalid day 0',
|
||||
structured_answer => {
|
||||
input => ['0 9 */0 * *'],
|
||||
operation => 'Crontab',
|
||||
result => 'Invalid day 0'
|
||||
}),
|
||||
|
||||
# Complex examples
|
||||
'crontab 42 12 3 Feb Sat' => test_zci('at 12:42pm on the 3rd and on Saturday in February',
|
||||
structured_answer => {
|
||||
input => ['42 12 3 Feb Sat'],
|
||||
operation => 'Crontab',
|
||||
result => 'at 12:42pm on the 3rd and on Saturday in February'
|
||||
}),
|
||||
);
|
||||
|
||||
done_testing;
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue