Skip to content

Commit 6b999d7

Browse files
authored
Day-of-week validation input checking (#554)
* Update documentation links in gemspec * Add rule_type validation specs * Validate occurrence passed to day_of_week * Update CHANGELOG * linting * Undo linting * Move rule specs to new folder * Move i18n specs to new folder * Check the actual values, not just the count * Update argument validations
1 parent 5eb51e3 commit 6b999d7

17 files changed

+154
-18
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1818
- When using a rule with hour_of_day validations, and asking for occurrences on the day that DST skips forward, valid occurrences would be missed. ([#464](https://github.com/seejohnrun/ice_cube/pull/464)) by [@jakebrady5](https://github.com/jakebrady5)
1919
- Include `exrules` when exporting a schedule to YAML, JSON or a Hash. ([#519](https://github.com/ice-cube-ruby/ice_cube/pull/519)) by [@pacso](https://github.com/pacso)
2020
- Documentation links updated to point to the new repository location. ([#553](https://github.com/ice-cube-ruby/ice_cube/pull/553)) by [@pacso](https://github.com/pacso)
21+
- Input validation added for day_of_week validator. Fixes infinite loops when invalid day_of_week occurrences are provided. ([#554](https://github.com/ice-cube-ruby/ice_cube/pull/554)) by [@pacso](https://github.com/pacso)
2122

2223
## [0.16.4] - 2021-10-21
2324
### Added

lib/ice_cube/rule.rb

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,7 @@ def from_hash(original_hash)
7373

7474
rule = IceCube::Rule.send(interval_type, hash[:interval] || 1)
7575

76-
if match[1] == "Weekly"
77-
rule.interval(hash[:interval] || 1, TimeUtil.wday_to_sym(hash[:week_start] || 0))
78-
end
79-
76+
rule.interval(hash[:interval] || 1, TimeUtil.wday_to_sym(hash[:week_start] || 0)) if rule.is_a? WeeklyRule
8077
rule.until(TimeUtil.deserialize_time(hash[:until])) if hash[:until]
8178
rule.count(hash[:count]) if hash[:count]
8279

lib/ice_cube/validations/day_of_week.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ class Validation
1515
attr_reader :day, :occ
1616

1717
def initialize(day, occ)
18+
raise ArgumentError, "Integer occurrence value required" unless occ.is_a?(Integer)
19+
raise ArgumentError, "Invalid day_of_week occurrence: #{occ.inspect}" if occ.zero? || occ.abs > 5
20+
1821
@day = day
1922
@occ = occ
2023
end

spec/examples/from_hash_spec.rb

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
require File.dirname(__FILE__) + "/../spec_helper"
2+
3+
module IceCube
4+
describe Rule, "from_hash" do
5+
describe "rule_type validations" do
6+
it "should raise an ArgumentError when the hash is empty" do
7+
expect { Rule.from_hash({}) }
8+
.to raise_error ArgumentError, "Invalid rule type"
9+
end
10+
11+
it "should raise an ArgumentError when the hash[:rule_type] is invalid" do
12+
expect { Rule.from_hash({rule_type: "IceCube::MadeUpIntervalRule"}) }
13+
.to raise_error ArgumentError, "Invalid rule frequency type: MadeUpInterval"
14+
end
15+
16+
it "returns a SecondlyRule when the hash[:rule_type] is secondly" do
17+
expect(Rule.from_hash({rule_type: "IceCube::SecondlyRule"})).to be_a SecondlyRule
18+
end
19+
20+
it "returns a MinutelyRule when the hash[:rule_type] is minutely" do
21+
expect(Rule.from_hash({rule_type: "IceCube::MinutelyRule"})).to be_a MinutelyRule
22+
end
23+
24+
it "returns a HourlyRule when the hash[:rule_type] is hourly" do
25+
expect(Rule.from_hash({rule_type: "IceCube::HourlyRule"})).to be_a HourlyRule
26+
end
27+
28+
it "returns a DailyRule when the hash[:rule_type] is daily" do
29+
expect(Rule.from_hash({rule_type: "IceCube::DailyRule"})).to be_a DailyRule
30+
end
31+
32+
it "returns a WeeklyRule when the hash[:rule_type] is weekly" do
33+
expect(Rule.from_hash({rule_type: "IceCube::WeeklyRule"})).to be_a WeeklyRule
34+
end
35+
36+
it "returns a MonthlyRule when the hash[:rule_type] is monthly" do
37+
expect(Rule.from_hash({rule_type: "IceCube::MonthlyRule"})).to be_a MonthlyRule
38+
end
39+
40+
it "returns a YearlyRule when the hash[:rule_type] is yearly" do
41+
expect(Rule.from_hash({rule_type: "IceCube::YearlyRule"})).to be_a YearlyRule
42+
end
43+
end
44+
45+
describe "creating monthly rule" do
46+
context "with valid day_of_week validations" do
47+
let(:input_hash) {
48+
{
49+
rule_type: "IceCube::MonthlyRule",
50+
interval: 1,
51+
validations: {
52+
day_of_week: {
53+
"0": [2],
54+
"1": [2],
55+
"2": [2],
56+
"3": [2],
57+
"4": [2],
58+
"5": [2],
59+
"6": [1, 2]
60+
},
61+
hour_of_day: 7,
62+
minute_of_hour: 19
63+
}
64+
}
65+
}
66+
67+
it "can provide the first occurrence" do
68+
rule = Rule.from_hash(input_hash)
69+
schedule = Schedule.new(Time.utc(2010, 1, 1, 0, 0, 0))
70+
schedule.add_recurrence_rule rule
71+
expect(schedule.first(10).map(&:to_time)).to eq([
72+
Time.utc(2010, 1, 2, 7, 19, 0),
73+
Time.utc(2010, 1, 8, 7, 19, 0),
74+
Time.utc(2010, 1, 9, 7, 19, 0),
75+
Time.utc(2010, 1, 10, 7, 19, 0),
76+
Time.utc(2010, 1, 11, 7, 19, 0),
77+
Time.utc(2010, 1, 12, 7, 19, 0),
78+
Time.utc(2010, 1, 13, 7, 19, 0),
79+
Time.utc(2010, 1, 14, 7, 19, 0),
80+
Time.utc(2010, 2, 6, 7, 19, 0),
81+
Time.utc(2010, 2, 8, 7, 19, 0)
82+
])
83+
end
84+
end
85+
86+
context "with invalid day_of_week validations" do
87+
let(:input_hash_with_zeroeth_occurrence) {
88+
{
89+
rule_type: "IceCube::MonthlyRule",
90+
interval: 1,
91+
validations: {
92+
day_of_week: {
93+
"1": [],
94+
"2": [0],
95+
"3": [],
96+
"4": []
97+
},
98+
hour_of_day: 7,
99+
minute_of_hour: 19
100+
}
101+
}
102+
}
103+
let(:input_hash_with_sixth_occurrence) {
104+
{
105+
rule_type: "IceCube::MonthlyRule",
106+
interval: 1,
107+
validations: {
108+
day_of_week: {
109+
"1": [],
110+
"2": [6],
111+
"3": [],
112+
"4": []
113+
},
114+
hour_of_day: 7,
115+
minute_of_hour: 19
116+
}
117+
}
118+
}
119+
120+
it "should raise an ArgumentError" do
121+
expect { Rule.from_hash(input_hash_with_zeroeth_occurrence) }
122+
.to raise_error ArgumentError, "Invalid day_of_week occurrence: 0"
123+
expect { Rule.from_hash(input_hash_with_sixth_occurrence) }
124+
.to raise_error ArgumentError, "Invalid day_of_week occurrence: 6"
125+
end
126+
end
127+
end
128+
end
129+
end

spec/examples/time_util_spec.rb

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,32 +42,38 @@ module IceCube
4242
end
4343

4444
describe :wday_to_sym do
45-
it "converts 0..6 to weekday symbols" do
46-
expect(TimeUtil.wday_to_sym(1)).to eq(:monday)
47-
end
45+
[:sunday, :monday, :tuesday, :wednesday, :thursday, :friday, :saturday].each_with_index do |sym, i|
46+
it "converts #{i} to weekday symbol :#{sym}" do
47+
expect(TimeUtil.wday_to_sym(i)).to eq(sym)
48+
end
4849

49-
it "returns weekday symbols as is" do
50-
expect(TimeUtil.wday_to_sym(:monday)).to eq(:monday)
50+
it "returns :#{sym} when passed :#{sym}" do
51+
expect(TimeUtil.wday_to_sym(sym)).to eq(sym)
52+
end
5153
end
5254

5355
it "raises an error for bad input" do
5456
expect { TimeUtil.wday_to_sym(:anyday) }.to raise_error(ArgumentError)
55-
expect { TimeUtil.wday_to_sym(17) }.to raise_error(ArgumentError)
57+
expect { TimeUtil.wday_to_sym(8) }.to raise_error(ArgumentError)
58+
expect { TimeUtil.wday_to_sym(-1) }.to raise_error(ArgumentError)
5659
end
5760
end
5861

5962
describe :sym_to_wday do
60-
it "converts weekday symbols to 0..6 wday numbers" do
61-
expect(TimeUtil.sym_to_wday(:monday)).to eq(1)
62-
end
63+
[:sunday, :monday, :tuesday, :wednesday, :thursday, :friday, :saturday].each_with_index do |sym, i|
64+
it "converts :#{sym} to integer #{i}" do
65+
expect(TimeUtil.sym_to_wday(sym)).to eq(i)
66+
end
6367

64-
it "returns wday numbers as is" do
65-
expect(TimeUtil.sym_to_wday(1)).to eq(1)
68+
it "returns #{i} when passed #{i}" do
69+
expect(TimeUtil.sym_to_wday(i)).to eq(i)
70+
end
6671
end
6772

6873
it "raises an error for bad input" do
6974
expect { TimeUtil.sym_to_wday(:anyday) }.to raise_error(ArgumentError)
70-
expect { TimeUtil.sym_to_wday(17) }.to raise_error(ArgumentError)
75+
expect { TimeUtil.sym_to_wday(-1) }.to raise_error(ArgumentError)
76+
expect { TimeUtil.sym_to_wday(8) }.to raise_error(ArgumentError)
7177
end
7278
end
7379

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)