crontab_syntax_checker 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "shoulda", ">= 0"
10
+ gem "rdoc", "~> 3.12"
11
+ gem "bundler", "~> 1.0"
12
+ gem "jeweler", "~> 2.0.1"
13
+ gem "simplecov", ">= 0"
14
+ end
data/License.txt ADDED
@@ -0,0 +1,7 @@
1
+ Copyright (c) 2011 Stephen Sloan
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,83 @@
1
+ # Crontab Syntax Checker - Validate crontab entries
2
+
3
+ Ruby gem to validate an entry that will be used in [crontab](http://www.manpagez.com/man/5/crontab/ "man 5 crontab").
4
+
5
+ ## Quick start examples
6
+
7
+ The crontab syntax checker is simple to use. These examples demonstrate three ways to quickly check that an entry is formatted correctly.
8
+
9
+ ### Example 1 - Verify from a string
10
+
11
+ You may input your candidate crontab entry as a string to the verify_crontab_line() function:
12
+
13
+ ```ruby
14
+ > require 'crontab_syntax_checker'
15
+ => true
16
+ > verify_crontab_line("5,35 */2 10-20,25-30 * 1-5 /foo/var | spam - > eggs.log")
17
+ => "5,35 */2 10-20,25-30 * 1-5 /foo/var | spam - > eggs.log"
18
+ ```
19
+
20
+ A string representation is returned upon success. A RuntimeError is raised when the format is invalid.
21
+
22
+ ### Example 2 - Verify from a hash
23
+
24
+ Another way to validate entries is by breaking up the crontab fields into a hash:
25
+
26
+ ```ruby
27
+ > require 'crontab_syntax_checker'
28
+ => true
29
+ > verify_crontab_hash(
30
+ :minute=>"5,35",
31
+ :hour=>"*/2",
32
+ :day=>"10-20,25-30",
33
+ :month=>"*",
34
+ :weekday=>"1-5",
35
+ :command=>"/foo/var | spam - > eggs.log")
36
+ => "5,35 */2 10-20,25-30 * 1-5 /foo/var | spam - > eggs.log"
37
+ ```
38
+
39
+ A string representation is returned upon success. A RuntimeError is raised when the format is invalid.
40
+
41
+ ### Example 3 - Using an object
42
+
43
+ Finally you can create a CrontabLine object directly and use setter methods for each field, which will be validated as they are set. For example:
44
+
45
+ ```ruby
46
+ > require 'crontab_syntax_checker'
47
+ => true
48
+ > crontab = CrontabLine.new
49
+ => #<CrontabLine:0x100... >
50
+ > crontab.minute = "5,35"
51
+ => "5,35"
52
+ > crontab.hour = "*/2"
53
+ => "*/2"
54
+ > crontab.day = "10-20,25-30"
55
+ => "10-20,25-30"
56
+ > crontab.month = "*"
57
+ => "*"
58
+ > crontab.weekday = "1-5"
59
+ => "1-5"
60
+ > crontab.command = "/foo/var | spam - > eggs.log"
61
+ => "/foo/var | spam - > eggs.log"
62
+ > crontab.to_s
63
+ => "5,35 */2 10-20,25-30 * 1-5 /foo/var | spam - > eggs.log"
64
+ ```
65
+
66
+ When no RuntimeError is raised, the crontab field is valid.
67
+
68
+ # Notes
69
+
70
+ Keep in mind that the verify functions or CrontabLine#to_s may not return exactly the same string as your input. The output, though possibly not equal, should be equivalent crontab syntax. If a crontab list in a field contains an asterisk, with no stepping indicated, then the entire field will be converted to an asterisk. Extra white space in the command field will be truncated. If this is a concern, use your own input in crontab after it has been validated.
71
+
72
+ The crontab validation here is based on the man 5 crontab file syntax description. Supported fields are asterisks, numbers, ranges, lists, and stepping (for ranges and asterisks). Numbers must be within the valid range as per the man file. Not supported are macro/named times. See the man file for more info.
73
+
74
+ # Credits
75
+
76
+ Crontab Syntax Checker is maintained by [Stephen Sloan](https://github.com/SteveSJ76) and is funded by [BookRenter.com](http://www.bookrenter.com "BookRenter.com").
77
+
78
+ ![BookRenter.com Logo](http://assets0.bookrenter.com/images/header/bookrenter_logo.gif "BookRenter.com")
79
+
80
+
81
+ # Copyright
82
+
83
+ Copyright (c) 2011 Stephen Sloan, Bookrenter.com. See LICENSE.txt for further details.
data/Rakefile ADDED
@@ -0,0 +1,50 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://guides.rubygems.org/specification-reference/ for more options
17
+ gem.name = 'crontab_syntax_checker'
18
+ gem.homepage = 'https://github.com/bkr/crontab_syntax_checker'
19
+ gem.summary = 'Validate an entry that will be used in crontab'
20
+ gem.license = "MIT"
21
+ gem.email = 'steve@stevesloan.com'
22
+ gem.authors = ['Stephen Sloan']
23
+ # dependencies defined in Gemfile
24
+ end
25
+ Jeweler::RubygemsDotOrgTasks.new
26
+
27
+ require 'rake/testtask'
28
+ Rake::TestTask.new(:test) do |test|
29
+ test.libs << 'lib' << 'test'
30
+ test.pattern = 'test/**/test_*.rb'
31
+ test.verbose = true
32
+ end
33
+
34
+ desc "Code coverage detail"
35
+ task :simplecov do
36
+ ENV['COVERAGE'] = "true"
37
+ Rake::Task['test'].execute
38
+ end
39
+
40
+ task :default => :test
41
+
42
+ require 'rdoc/task'
43
+ Rake::RDocTask.new do |rdoc|
44
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
45
+
46
+ rdoc.rdoc_dir = 'rdoc'
47
+ rdoc.title = "helloworld #{version}"
48
+ rdoc.rdoc_files.include('README*')
49
+ rdoc.rdoc_files.include('lib/**/*.rb')
50
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,100 @@
1
+
2
+ class AbstractCrontabField
3
+ @@CRONTAB_FIELD_REGEX = /^(\*|(\d)+)(-(\d+))?(\/(\d+))?$/
4
+ @@START_GROUP_NUM = 1
5
+ @@STOP_GROUP_NUM = 4
6
+ @@STEP_GROUP_NUM = 6
7
+ @@ASTERISK_FIELD_REGEX = /^\*(\/(\d+))?$/
8
+ def initialize(start, stop=nil, step=nil)
9
+ @start = start.to_i
10
+ @stop = stop.nil? ? @start : stop.to_i
11
+ @step = step.nil? ? 1 : step.to_i
12
+ if @step > 1 and @stop == @start
13
+ raise "Stepping must be used with ranges or asterisk only"
14
+ end
15
+ end
16
+ def self.create_from_string(field_string)
17
+ md = @@CRONTAB_FIELD_REGEX.match(field_string)
18
+ if md
19
+ asterisk_md = @@ASTERISK_FIELD_REGEX.match(md[@@START_GROUP_NUM])
20
+ if asterisk_md
21
+ step = md[@@STEP_GROUP_NUM]
22
+ CrontabAsterisk.new(step)
23
+ else
24
+ start = md[@@START_GROUP_NUM]
25
+ stop = md[@@STOP_GROUP_NUM]
26
+ step = md[@@STEP_GROUP_NUM]
27
+ new(start, stop, step)
28
+ end
29
+ else
30
+ raise "Can't parse crontab field \"#{field_string}\""
31
+ end
32
+ end
33
+ def to_s
34
+ as_s = @start.to_s
35
+ as_s += "-#{@stop}" if @stop > @start
36
+ as_s += "/#{@step}" if @step > 1
37
+ as_s
38
+ end
39
+ end
40
+
41
+ class CrontabAsterisk < AbstractCrontabField
42
+ def initialize(step=nil)
43
+ step.nil? ? @step = 1 : @step = step.to_i
44
+ end
45
+ def to_s
46
+ as_s = '*'
47
+ as_s += "/#{@step}" if @step > 1
48
+ as_s
49
+ end
50
+ end
51
+
52
+ class CrontabMinute < AbstractCrontabField
53
+ @@min = 0
54
+ @@max = 59
55
+ def initialize(start, stop=nil, step=nil)
56
+ super(start, stop, step)
57
+ raise "Minute field #{@start} must not be greater than #{@@min}" if @start < @@min
58
+ raise "Minute field #{@stop} must not be greater than #{@@max}" if @stop > @@max
59
+ end
60
+ end
61
+
62
+ class CrontabHour < AbstractCrontabField
63
+ @@min = 0
64
+ @@max = 23
65
+ def initialize(start, stop=nil, step=nil)
66
+ super(start, stop, step)
67
+ raise "Hour field #{@start} must not be greater than #{@@min}" if @start < @@min
68
+ raise "Hour field #{@stop} must not be greater than #{@@max}" if @stop > @@max
69
+ end
70
+ end
71
+
72
+ class CrontabDay < AbstractCrontabField
73
+ @@min = 1
74
+ @@max = 31
75
+ def initialize(start, stop=nil, step=nil)
76
+ super(start, stop, step)
77
+ raise "Day field #{@start} must not be greater than #{@@min}" if @start < @@min
78
+ raise "Day field #{@stop} must not be greater than #{@@max}" if @stop > @@max
79
+ end
80
+ end
81
+
82
+ class CrontabMonth < AbstractCrontabField
83
+ @@min = 1
84
+ @@max = 12
85
+ def initialize(start, stop=nil, step=nil)
86
+ super(start, stop, step)
87
+ raise "Month field #{@start} must not be greater than #{@@min}" if @start < @@min
88
+ raise "Month field #{@stop} must not be greater than #{@@max}" if @stop > @@max
89
+ end
90
+ end
91
+
92
+ class CrontabWeekday < AbstractCrontabField
93
+ @@min = 0
94
+ @@max = 7
95
+ def initialize(start, stop=nil, step=nil)
96
+ super(start, stop, step)
97
+ raise "Weekday field #{@start} must not be greater than #{@@min}" if @start < @@min
98
+ raise "Weekday field #{@stop} must not be greater than #{@@max}" if @stop > @@max
99
+ end
100
+ end
@@ -0,0 +1,86 @@
1
+ require 'crontab_fields'
2
+ require 'crontab_line_base'
3
+
4
+ class CrontabLine < CrontabLineBase
5
+
6
+ cron_attr_accessor :minute, :hour, :day, :month, :weekday
7
+ attr_accessor :user
8
+ attr_reader :command
9
+
10
+ @@ENTRY_REGEX = /^([-\/,0-9*]+)\s+([-\/,0-9*]+)\s+([-\/,0-9*]+)\s+([-\/,0-9*]+)\s+([-\/,0-9*]+)\s+(.*)$/
11
+ @@MINUTE_GROUP_NUM = 1
12
+ @@HOUR_GROUP_NUM = 2
13
+ @@DAY_GROUP_NUM = 3
14
+ @@MONTH_GROUP_NUM = 4
15
+ @@WEEKDAY_GROUP_NUM = 5
16
+ @@COMMAND_GROUP_NUM = 6
17
+ @@SPACE_IN_LIST_REGEX = /\d+(-\d+(\/\d+)?)?,\s\d+/
18
+ def initialize
19
+ @minute = [CrontabAsterisk.new]
20
+ @hour = [CrontabAsterisk.new]
21
+ @day = [CrontabAsterisk.new]
22
+ @month = [CrontabAsterisk.new]
23
+ @weekday = [CrontabAsterisk.new]
24
+ @command = ""
25
+ @user = nil
26
+ end
27
+ def command=(value)
28
+ value = "" if value.nil?
29
+ value = value.to_s unless value.instance_of?(String)
30
+ @command = value
31
+ end
32
+ def self.create_by_hash(crontab_hash)
33
+ crontab = CrontabLine.new
34
+ crontab_hash.each() do |key, value|
35
+ crontab.send("#{key}=", value)
36
+ end
37
+ crontab
38
+ end
39
+ def self.create_by_entry(entry)
40
+ md = @@SPACE_IN_LIST_REGEX.match(entry)
41
+ if md
42
+ raise "I think you have a space in a crontab field (but I'm not very smart). " +
43
+ "Use 'create_by_hash()' instead to override me."
44
+ end
45
+ md = @@ENTRY_REGEX.match(entry)
46
+ if md
47
+ crontab = CrontabLine.new
48
+ crontab.minute = md[@@MINUTE_GROUP_NUM]
49
+ crontab.hour = md[@@HOUR_GROUP_NUM]
50
+ crontab.day = md[@@DAY_GROUP_NUM]
51
+ crontab.month = md[@@MONTH_GROUP_NUM]
52
+ crontab.weekday = md[@@WEEKDAY_GROUP_NUM]
53
+ crontab.command = md[@@COMMAND_GROUP_NUM]
54
+ crontab
55
+ else
56
+ raise "Entry did match expected pattern"
57
+ end
58
+ end
59
+ def to_s
60
+ fields = [minute, hour, day, month, weekday, command]
61
+ fields.insert(-2, user) unless user.nil?
62
+ fields.join(" ")
63
+ end
64
+ private
65
+ @@FIELD_CLASS_BY_PARAM = {
66
+ :@minute => CrontabMinute,
67
+ :@hour => CrontabHour,
68
+ :@day => CrontabDay,
69
+ :@month => CrontabMonth,
70
+ :@weekday => CrontabWeekday
71
+ }
72
+ def get_field_class(param)
73
+ @@FIELD_CLASS_BY_PARAM[param]
74
+ end
75
+ def param_setter(param, value)
76
+ raise "Crontab fields may not contain white-space characters" if value =~ /\s/
77
+ value = "*" if value.nil?
78
+ value = value.to_s unless value.instance_of? String
79
+ if value =~ /\*(,|$)/
80
+ instance_variable_set(param, [CrontabAsterisk.new])
81
+ else
82
+ minute_strings = value.split(',')
83
+ instance_variable_set(param, minute_strings.map {|min_s| (get_field_class(param)).create_from_string(min_s)})
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,14 @@
1
+ class CrontabLineBase
2
+ def self.make_cron_attr(field_sym)
3
+ field_str = field_sym.to_s
4
+ define_method(field_sym) do
5
+ instance_variable_get("@#{field_str}").join(',')
6
+ end
7
+ define_method("#{field_str}=") do |value|
8
+ param_setter("@#{field_str}".to_sym, value)
9
+ end
10
+ end
11
+ def self.cron_attr_accessor(*args)
12
+ args.each { |arg| self.make_cron_attr(arg) }
13
+ end
14
+ end
@@ -0,0 +1,17 @@
1
+ require 'crontab_line'
2
+
3
+ def verify_crontab_line(crontab_line)
4
+ begin
5
+ CrontabLine.create_by_entry(crontab_line).to_s
6
+ rescue RuntimeError => e
7
+ raise "Invalid entry \"#{crontab_line}\": #{e.message}"
8
+ end
9
+ end
10
+
11
+ def verify_crontab_hash(crontab_hash)
12
+ begin
13
+ CrontabLine.create_by_hash(crontab_hash).to_s
14
+ rescue RuntimeError => e
15
+ raise "Invalid entry \"#{crontab_hash.inspect}\": #{e.message}"
16
+ end
17
+ end
@@ -0,0 +1,513 @@
1
+ $:.unshift(File.join("..","lib",File.dirname(__FILE__)))
2
+ require 'test/unit'
3
+ require 'crontab_syntax_checker'
4
+
5
+ class TestCrontabLineGetters < Test::Unit::TestCase
6
+ def setup
7
+ @crontab = CrontabLine.new
8
+ end
9
+ def test_default_minute
10
+ assert_equal '*', @crontab.minute, "Default minute is wrong"
11
+ end
12
+ def test_default_hour
13
+ assert_equal '*', @crontab.hour, "Default hour is wrong"
14
+ end
15
+ def test_default_day
16
+ assert_equal '*', @crontab.day, "Default day is wrong"
17
+ end
18
+ def test_default_month
19
+ assert_equal '*', @crontab.month, "Default month is wrong"
20
+ end
21
+ def test_default_weekday
22
+ assert_equal '*', @crontab.weekday, "Default weekday is wrong"
23
+ end
24
+ def test_default_command
25
+ assert_equal '', @crontab.command, "Default command is wrong"
26
+ end
27
+ end
28
+
29
+ class TestCrontabLineSetters < Test::Unit::TestCase
30
+ def setup
31
+ @crontab = CrontabLine.new
32
+ end
33
+ def test_set_minute_to_1
34
+ @crontab.minute = "1"
35
+ assert_equal "1", @crontab.minute, "The minute value was incorrect"
36
+ end
37
+ def test_set_minute_to_1_by_int
38
+ @crontab.minute = 1
39
+ assert_equal "1", @crontab.minute, "The minute value was incorrect"
40
+ end
41
+ def test_set_minute_to_1_2_3
42
+ set_to = "1,2,3"
43
+ @crontab.minute = set_to
44
+ assert_equal set_to, @crontab.minute, "The minute value was incorrect"
45
+ end
46
+ def test_set_minute_to_nil
47
+ @crontab.minute = nil
48
+ assert_equal '*', @crontab.minute, "The minute value was incorrect"
49
+ end
50
+ def test_set_hour_to_1
51
+ @crontab.hour = "1"
52
+ assert_equal "1", @crontab.hour, "The hour value was incorrect"
53
+ end
54
+ def test_set_hour_to_1_by_int
55
+ @crontab.hour = 1
56
+ assert_equal "1", @crontab.hour, "The hour value was incorrect"
57
+ end
58
+ def test_set_hour_to_1_2_3
59
+ set_to = "1,2,3"
60
+ @crontab.hour = set_to
61
+ assert_equal set_to, @crontab.hour, "The hour value was incorrect"
62
+ end
63
+ def test_set_hour_to_nil
64
+ @crontab.hour = nil
65
+ assert_equal '*', @crontab.hour, "The hour value was incorrect"
66
+ end
67
+ def test_set_day_to_1
68
+ @crontab.day = "1"
69
+ assert_equal "1", @crontab.day, "The day value was incorrect"
70
+ end
71
+ def test_set_day_to_1_by_int
72
+ @crontab.day = 1
73
+ assert_equal "1", @crontab.day, "The day value was incorrect"
74
+ end
75
+ def test_set_day_to_1_2_3
76
+ set_to = "1,2,3"
77
+ @crontab.day = set_to
78
+ assert_equal set_to, @crontab.day, "The day value was incorrect"
79
+ end
80
+ def test_set_day_to_nil
81
+ @crontab.day = nil
82
+ assert_equal '*', @crontab.day, "The day value was incorrect"
83
+ end
84
+ def test_set_month_to_1
85
+ @crontab.month = "1"
86
+ assert_equal '1', @crontab.month, "The month value was incorrect"
87
+ end
88
+ def test_set_month_to_1_by_int
89
+ @crontab.month = 1
90
+ assert_equal '1', @crontab.month, "The month value was incorrect"
91
+ end
92
+ def test_set_month_to_1_2_3
93
+ set_to = '1,2,3'
94
+ @crontab.month = set_to
95
+ assert_equal set_to, @crontab.month, "The month value was incorrect"
96
+ end
97
+ def test_set_month_to_nil
98
+ @crontab.month = nil
99
+ assert_equal '*', @crontab.month, "The month value was incorrect"
100
+ end
101
+ def test_set_weekday_to_1
102
+ @crontab.weekday = '1'
103
+ assert_equal '1', @crontab.weekday, "The weekday value was incorrect"
104
+ end
105
+ def test_set_weekday_to_1_by_int
106
+ @crontab.weekday = 1
107
+ assert_equal '1', @crontab.weekday, "The weekday value was incorrect"
108
+ end
109
+ def test_set_weekday_to_1_2_3
110
+ set_to = '1,2,3'
111
+ @crontab.weekday = set_to
112
+ assert_equal set_to, @crontab.weekday, "The weekday value was incorrect"
113
+ end
114
+ def test_set_weekday_to_nil
115
+ @crontab.weekday = nil
116
+ assert_equal '*', @crontab.weekday, "The weekday value was incorrect"
117
+ end
118
+ def test_set_command_no_space
119
+ @crontab.command = "foobar"
120
+ assert_equal "foobar", @crontab.command, "The command value was incorrect"
121
+ end
122
+ def test_set_command_with_space
123
+ set_to = "foo -bar | spam - > eggs.log"
124
+ @crontab.command = set_to
125
+ assert_equal set_to, @crontab.command, "The command value was incorrect"
126
+ end
127
+ def test_set_command_nill
128
+ @crontab.command = nil
129
+ assert_equal "", @crontab.command, "The command value was incorrect"
130
+ end
131
+ end
132
+
133
+ class TestCrontabLineValidNumbers < Test::Unit::TestCase
134
+ def setup
135
+ @crontab = CrontabLine.new
136
+ end
137
+ def test_minute_too_low
138
+ assert_raise(RuntimeError) { @crontab.minute = -1 }
139
+ assert_raise(RuntimeError) { @crontab.minute = -10 }
140
+ assert_raise(RuntimeError) { @crontab.minute = -100 }
141
+ end
142
+ def test_minute_just_right
143
+ (0..59).to_enum.each do |i|
144
+ assert_nothing_raised(RuntimeError) { @crontab.minute = i }
145
+ assert_equal i.to_s, @crontab.minute, "Minute value didn't match"
146
+ end
147
+ end
148
+ def test_minute_too_high
149
+ assert_raise(RuntimeError) { @crontab.minute = 60 }
150
+ assert_raise(RuntimeError) { @crontab.minute = 100 }
151
+ assert_raise(RuntimeError) { @crontab.minute = 1000 }
152
+ end
153
+ def test_hour_too_low
154
+ assert_raise(RuntimeError) { @crontab.hour = -1 }
155
+ assert_raise(RuntimeError) { @crontab.hour = -10 }
156
+ assert_raise(RuntimeError) { @crontab.hour = -100 }
157
+ end
158
+ def test_hour_just_right
159
+ (0..23).to_enum.each do |i|
160
+ assert_nothing_raised(RuntimeError) { @crontab.hour = i }
161
+ assert_equal i.to_s, @crontab.hour, "Hour value didn't match"
162
+ end
163
+ end
164
+ def test_hour_too_high
165
+ assert_raise(RuntimeError) { @crontab.hour = 24 }
166
+ assert_raise(RuntimeError) { @crontab.hour = 240 }
167
+ assert_raise(RuntimeError) { @crontab.hour = 2400 }
168
+ end
169
+ def test_day_too_low
170
+ assert_raise(RuntimeError) { @crontab.day = 0 }
171
+ assert_raise(RuntimeError) { @crontab.day = -1 }
172
+ assert_raise(RuntimeError) { @crontab.day = -10 }
173
+ end
174
+ def test_day_just_right
175
+ (1..31).to_enum.each do |i|
176
+ assert_nothing_raised(RuntimeError) { @crontab.day = i }
177
+ assert_equal i.to_s, @crontab.day, "Day value didn't match"
178
+ end
179
+ end
180
+ def test_day_too_high
181
+ assert_raise(RuntimeError) { @crontab.day = 32 }
182
+ assert_raise(RuntimeError) { @crontab.day = 320 }
183
+ assert_raise(RuntimeError) { @crontab.day = 3200 }
184
+ end
185
+ def test_month_too_low
186
+ assert_raise(RuntimeError) { @crontab.month = 0 }
187
+ assert_raise(RuntimeError) { @crontab.month = -1 }
188
+ assert_raise(RuntimeError) { @crontab.month = -10 }
189
+ end
190
+ def test_month_just_right
191
+ (1..12).to_enum.each do |i|
192
+ assert_nothing_raised(RuntimeError) { @crontab.month = i }
193
+ assert_equal i.to_s, @crontab.month, "Month value didn't match"
194
+ end
195
+ end
196
+ def test_month_too_high
197
+ assert_raise(RuntimeError) { @crontab.month = 13 }
198
+ assert_raise(RuntimeError) { @crontab.month = 100 }
199
+ assert_raise(RuntimeError) { @crontab.month = 1000 }
200
+ end
201
+ def test_weekday_too_low
202
+ assert_raise(RuntimeError) { @crontab.weekday = -1 }
203
+ assert_raise(RuntimeError) { @crontab.weekday = -10 }
204
+ assert_raise(RuntimeError) { @crontab.weekday = -100 }
205
+ end
206
+ def test_weekday_just_right
207
+ (0..7).to_enum.each do |i|
208
+ assert_nothing_raised(RuntimeError) { @crontab.weekday = i }
209
+ assert_equal i.to_s, @crontab.weekday, "Weekday value didn't match"
210
+ end
211
+ end
212
+ def test_weekday_too_high
213
+ assert_raise(RuntimeError) { @crontab.weekday = 8 }
214
+ assert_raise(RuntimeError) { @crontab.weekday = 10 }
215
+ assert_raise(RuntimeError) { @crontab.weekday = 100 }
216
+ end
217
+ end
218
+
219
+ class TestCrontabLineRanges < Test::Unit::TestCase
220
+ def setup
221
+ @crontab = CrontabLine.new
222
+ end
223
+ def test_minute_range_low_end
224
+ assert_nothing_raised(RuntimeError) { @crontab.minute = "0-5" }
225
+ assert_equal "0-5", @crontab.minute
226
+ end
227
+ def test_minute_range_high_end
228
+ assert_nothing_raised(RuntimeError) { @crontab.minute = "54-59"}
229
+ assert_equal "54-59", @crontab.minute
230
+ end
231
+ def test_minute_entire_range
232
+ assert_nothing_raised(RuntimeError) { @crontab.minute = "0-59" }
233
+ assert_equal "0-59", @crontab.minute
234
+ end
235
+ def test_minute_multiple_ranges
236
+ set_to = "0-5,10-15,50-59"
237
+ assert_nothing_raised(RuntimeError) { @crontab.minute = set_to }
238
+ assert_equal set_to, @crontab.minute
239
+ end
240
+ def test_minute_out_of_range_high
241
+ assert_raise(RuntimeError) { @crontab.minute = "0-100" }
242
+ end
243
+ def test_minute_out_of_range_low
244
+ assert_raise(RuntimeError) { @crontab.minute = "-1-59" }
245
+ end
246
+ def test_minute_multiple_out_of_range
247
+ assert_raise(RuntimeError) { @crontab.minute = "0-5,50-100" }
248
+ end
249
+ def test_hour_range_low_end
250
+ assert_nothing_raised(RuntimeError) { @crontab.hour = "0-5" }
251
+ assert_equal "0-5", @crontab.hour
252
+ end
253
+ def test_hour_range_high_end
254
+ assert_nothing_raised(RuntimeError) { @crontab.hour = "18-23" }
255
+ assert_equal "18-23", @crontab.hour
256
+ end
257
+ def test_hour_entire_range
258
+ assert_nothing_raised(RuntimeError) { @crontab.hour = "0-23" }
259
+ assert_equal "0-23", @crontab.hour
260
+ end
261
+ def test_hour_multiple_ranges
262
+ set_to = "0-1,2-3,8-10,15-23"
263
+ assert_nothing_raised(RuntimeError) { @crontab.hour = set_to }
264
+ assert_equal set_to, @crontab.hour
265
+ end
266
+ def test_hour_out_of_range_high
267
+ assert_raise(RuntimeError) { @crontab.hour = "0-100" }
268
+ end
269
+ def test_hour_out_of_range_low
270
+ assert_raise(RuntimeError) { @crontab.hour = "-1-23" }
271
+ end
272
+ def test_hour_multiple_out_of_range
273
+ assert_raise(RuntimeError) { @crontab.hour = "0-10,15-24" }
274
+ end
275
+ def test_day_range_low_end
276
+ assert_nothing_raised(RuntimeError) { @crontab.day = "1-6" }
277
+ assert_equal "1-6", @crontab.day
278
+ end
279
+ def test_day_range_high_end
280
+ assert_nothing_raised(RuntimeError) { @crontab.day = "26-31"}
281
+ assert_equal "26-31", @crontab.day
282
+ end
283
+ def test_day_entire_range
284
+ assert_nothing_raised(RuntimeError) { @crontab.day = "1-31" }
285
+ assert_equal "1-31", @crontab.day
286
+ end
287
+ def test_day_multiple_ranges
288
+ set_to = "1-5,10-15,20-30"
289
+ assert_nothing_raised(RuntimeError) { @crontab.day = set_to }
290
+ assert_equal set_to, @crontab.day
291
+ end
292
+ def test_day_out_of_range_high
293
+ assert_raise(RuntimeError) { @crontab.day = "0-100" }
294
+ end
295
+ def test_day_out_of_range_low
296
+ assert_raise(RuntimeError) { @crontab.day = "-1-31" }
297
+ end
298
+ def test_day_multiple_out_of_range
299
+ assert_raise(RuntimeError) { @crontab.day = "0-10,30-35,15-25" }
300
+ end
301
+ def test_month_range_low_end
302
+ assert_nothing_raised(RuntimeError) { @crontab.month = "1-6" }
303
+ assert_equal "1-6", @crontab.month
304
+ end
305
+ def test_month_range_high_end
306
+ assert_nothing_raised(RuntimeError) { @crontab.month = "5-12"}
307
+ assert_equal "5-12", @crontab.month
308
+ end
309
+ def test_month_entire_range
310
+ assert_nothing_raised(RuntimeError) { @crontab.month = "1-12" }
311
+ assert_equal "1-12", @crontab.month
312
+ end
313
+ def test_month_multiple_ranges
314
+ set_to = "1-3,5-8,11-12"
315
+ assert_nothing_raised(RuntimeError) { @crontab.month = set_to }
316
+ assert_equal set_to, @crontab.month
317
+ end
318
+ def test_month_out_of_range_high
319
+ assert_raise(RuntimeError) { @crontab.month = "0-100" }
320
+ end
321
+ def test_month_out_of_range_low
322
+ assert_raise(RuntimeError) { @crontab.month = "-1-12" }
323
+ end
324
+ def test_month_multiple_out_of_range
325
+ assert_raise(RuntimeError) { @crontab.month = "1-3,5-8,11-14" }
326
+ end
327
+ def test_weekday_range_low_end
328
+ assert_nothing_raised(RuntimeError) { @crontab.weekday = "0-3" }
329
+ assert_equal "0-3", @crontab.weekday
330
+ end
331
+ def test_weekday_range_high_end
332
+ assert_nothing_raised(RuntimeError) { @crontab.weekday = "4-7" }
333
+ assert_equal "4-7", @crontab.weekday
334
+ end
335
+ def test_weekday_entire_range
336
+ assert_nothing_raised(RuntimeError) { @crontab.weekday = "0-7" }
337
+ assert_equal "0-7", @crontab.weekday
338
+ end
339
+ def test_weekday_multiple_ranges
340
+ set_to = "1-2,3-4,6-7"
341
+ assert_nothing_raised(RuntimeError) { @crontab.weekday = set_to }
342
+ assert_equal set_to, @crontab.weekday
343
+ end
344
+ def test_weekday_out_of_range_high
345
+ assert_raise(RuntimeError) { @crontab.weekday = "0-100" }
346
+ end
347
+ def test_weekday_out_of_range_low
348
+ assert_raise(RuntimeError) { @crontab.weekday = "-1-7" }
349
+ end
350
+ def test_weekday_multiple_out_of_range
351
+ assert_raise(RuntimeError) { @crontab.weekday = "0-2,4-10,7" }
352
+ end
353
+ end
354
+
355
+ class TestCrontabLineStepping < Test::Unit::TestCase
356
+ def setup
357
+ @crontab = CrontabLine.new
358
+ end
359
+ def test_minute_asterix_with_stepping
360
+ set_to = '*/2'
361
+ assert_nothing_raised(RuntimeError) { @crontab.minute = set_to }
362
+ assert_equal set_to, @crontab.minute
363
+ end
364
+ def test_minute_range_with_stepping
365
+ set_to = '0-30/5'
366
+ assert_nothing_raised(RuntimeError) { @crontab.minute = set_to }
367
+ assert_equal set_to, @crontab.minute
368
+ end
369
+ def test_minute_stepping_with_multiple_ranges
370
+ set_to = '0-10/2,12,13-15,18-21/3'
371
+ assert_nothing_raised(RuntimeError) { @crontab.minute = set_to }
372
+ assert_equal set_to, @crontab.minute
373
+ end
374
+ def test_minute_stepping_with_no_range_raises
375
+ set_to = '10/5'
376
+ assert_raise(RuntimeError) { @crontab.minute = set_to }
377
+ end
378
+ def test_hour_asterix_with_stepping
379
+ set_to = '*/2'
380
+ assert_nothing_raised(RuntimeError) { @crontab.hour = set_to }
381
+ assert_equal set_to, @crontab.hour
382
+ end
383
+ def test_hour_range_with_stepping
384
+ set_to = '0-22/2'
385
+ assert_nothing_raised(RuntimeError) { @crontab.hour = set_to }
386
+ assert_equal set_to, @crontab.hour
387
+ end
388
+ def test_hour_stepping_with_multiple_ranges
389
+ set_to = '0-10/2,16-22/2'
390
+ assert_nothing_raised(RuntimeError) { @crontab.hour = set_to }
391
+ assert_equal set_to, @crontab.hour
392
+ end
393
+ def test_hour_stepping_with_no_range_raises
394
+ set_to = '10/5'
395
+ assert_raise(RuntimeError) { @crontab.hour = set_to }
396
+ end
397
+ def test_day_asterix_with_stepping
398
+ set_to = '*/2'
399
+ assert_nothing_raised(RuntimeError) { @crontab.day = set_to }
400
+ assert_equal set_to, @crontab.day
401
+ end
402
+ def test_day_range_with_stepping
403
+ set_to = '1-30/5'
404
+ assert_nothing_raised(RuntimeError) { @crontab.day = set_to }
405
+ assert_equal set_to, @crontab.day
406
+ end
407
+ def test_day_stepping_with_multiple_ranges
408
+ set_to = '1-11/2,15,20-30/2'
409
+ assert_nothing_raised(RuntimeError) { @crontab.day = set_to }
410
+ assert_equal set_to, @crontab.day
411
+ end
412
+ def test_day_stepping_with_no_range_raises
413
+ set_to = '10/5'
414
+ assert_raise(RuntimeError) { @crontab.day = set_to }
415
+ end
416
+ def test_month_asterix_with_stepping
417
+ set_to = '*/2'
418
+ assert_nothing_raised(RuntimeError) { @crontab.month = set_to }
419
+ assert_equal set_to, @crontab.month
420
+ end
421
+ def test_month_range_with_stepping
422
+ set_to = '2-12/2'
423
+ assert_nothing_raised(RuntimeError) { @crontab.month = set_to }
424
+ assert_equal set_to, @crontab.month
425
+ end
426
+ def test_month_stepping_with_multiple_ranges
427
+ set_to = '1-3/2,5,7-11/2'
428
+ assert_nothing_raised(RuntimeError) { @crontab.month = set_to }
429
+ assert_equal set_to, @crontab.month
430
+ end
431
+ def test_month_stepping_with_no_range_raises
432
+ set_to = '10/5'
433
+ assert_raise(RuntimeError) { @crontab.month = set_to }
434
+ end
435
+ def test_weekday_asterix_with_stepping
436
+ set_to = '*/2'
437
+ assert_nothing_raised(RuntimeError) { @crontab.weekday = set_to }
438
+ assert_equal set_to, @crontab.weekday
439
+ end
440
+ def test_weekday_range_with_stepping
441
+ set_to = '0-4/2'
442
+ assert_nothing_raised(RuntimeError) { @crontab.weekday = set_to }
443
+ assert_equal set_to, @crontab.weekday
444
+ end
445
+ def test_weekday_stepping_with_multiple_ranges
446
+ set_to = '0-3/3,4-6/2'
447
+ assert_nothing_raised(RuntimeError) { @crontab.weekday = set_to }
448
+ assert_equal set_to, @crontab.weekday
449
+ end
450
+ def test_weekday_stepping_with_no_range_raises
451
+ set_to = '3/5'
452
+ assert_raise(RuntimeError) { @crontab.weekday = set_to }
453
+ end
454
+ end
455
+
456
+ class TestVerifyCrontabLine < Test::Unit::TestCase
457
+ def test_valid_crontab_line
458
+ assert_nothing_raised(RuntimeError) { verify_crontab_line("5,35 */2 10-20,25-30 * 1-5 /foo/var | spam - > eggs.log") }
459
+ end
460
+ def test_invalid_crontab_line
461
+ assert_raise(RuntimeError) { verify_crontab_line("5, 35 */2 10-20,25-30 13 1-5 /foo/var | spam - > eggs.log") }
462
+ end
463
+ end
464
+
465
+ class TestVerifyCrontabHash < Test::Unit::TestCase
466
+ def test_valid_crontab_hash
467
+ crontab_hash = { :minute=>"5,35", :hour=>"*/2", :day=>"10-20,25-30", :month=>"*", :weekday=>"1-5", :command=>"/foo/var | spam - > eggs.log" }
468
+ assert_nothing_raised(RuntimeError) do
469
+ verify_crontab_hash(crontab_hash)
470
+ end
471
+ end
472
+ def test_invalid_crontab_hash
473
+ crontab_hash = { :minute=>"5, 35", :hour=>"*/2", :day=>"10-20,25-30", :month=>"13", :weekday=>"1-5", :command=>"/foo/var | spam - > eggs.log" }
474
+ assert_raise(RuntimeError) do
475
+ verify_crontab_hash(crontab_hash)
476
+ end
477
+ end
478
+ def test_valid_crontab_hash_with_user
479
+ crontab_hash = { :minute=>"5,35", :hour=>"*/2", :day=>"10-20,25-30", :month=>"*", :weekday=>"1-5", :user=>"root", :command=>"/foo/var | spam - > eggs.log" }
480
+ assert_nothing_raised(RuntimeError) do
481
+ result = verify_crontab_hash(crontab_hash)
482
+ end
483
+ end
484
+ end
485
+
486
+ class TestCrontabstringOutput < Test::Unit::TestCase
487
+ def setup
488
+ @crontab = CrontabLine.new
489
+ @crontab.minute = "*"
490
+ @crontab.hour = "*"
491
+ @crontab.day = "*"
492
+ @crontab.month = "*"
493
+ @crontab.weekday = "*"
494
+ @crontab.command = "/foo/var | spam - > eggs.log"
495
+ end
496
+ def test_to_string_output
497
+ assert_equal "* * * * * /foo/var | spam - > eggs.log", @crontab.to_s, "Converting crontab to string failed"
498
+ end
499
+ def test_to_string_output_with_user
500
+ @crontab.user = "root"
501
+ assert_equal "* * * * * root /foo/var | spam - > eggs.log", @crontab.to_s, "Converting crontab to string (with user) failed"
502
+ end
503
+ end
504
+
505
+ class TestCrontabstringOutputFromHash < Test::Unit::TestCase
506
+ def setup
507
+ @crontab_hash = { :minute=>"5,35", :hour=>"*/2", :day=>"10-20,25-30", :month=>"*", :weekday=>"1-5", :user=>"root", :command=>"/foo/var | spam - > eggs.log" }
508
+ @expected_string = "5,35 */2 10-20,25-30 * 1-5 root /foo/var | spam - > eggs.log"
509
+ end
510
+ def test_to_string_output_with_user_from_hash
511
+ assert @expected_string, verify_crontab_hash(@crontab_hash)
512
+ end
513
+ end
metadata ADDED
@@ -0,0 +1,139 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: crontab_syntax_checker
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Stephen Sloan
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-04-01 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: shoulda
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rdoc
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '3.12'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '3.12'
46
+ - !ruby/object:Gem::Dependency
47
+ name: bundler
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '1.0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '1.0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: jeweler
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: 2.0.1
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: 2.0.1
78
+ - !ruby/object:Gem::Dependency
79
+ name: simplecov
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ description:
95
+ email: steve@stevesloan.com
96
+ executables: []
97
+ extensions: []
98
+ extra_rdoc_files:
99
+ - README.md
100
+ files:
101
+ - Gemfile
102
+ - License.txt
103
+ - README.md
104
+ - Rakefile
105
+ - VERSION
106
+ - lib/crontab_fields.rb
107
+ - lib/crontab_line.rb
108
+ - lib/crontab_line_base.rb
109
+ - lib/crontab_syntax_checker.rb
110
+ - test/test_crontab_line.rb
111
+ homepage: https://github.com/bkr/crontab_syntax_checker
112
+ licenses:
113
+ - MIT
114
+ post_install_message:
115
+ rdoc_options: []
116
+ require_paths:
117
+ - lib
118
+ required_ruby_version: !ruby/object:Gem::Requirement
119
+ none: false
120
+ requirements:
121
+ - - ! '>='
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ segments:
125
+ - 0
126
+ hash: 3912384251142507461
127
+ required_rubygems_version: !ruby/object:Gem::Requirement
128
+ none: false
129
+ requirements:
130
+ - - ! '>='
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ requirements: []
134
+ rubyforge_project:
135
+ rubygems_version: 1.8.23.2
136
+ signing_key:
137
+ specification_version: 3
138
+ summary: Validate an entry that will be used in crontab
139
+ test_files: []