stephenrichards-holiday_calendar 1.0.10
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rb +82 -0
- data/config/fr.yaml +72 -0
- data/config/uk.yaml +54 -0
- data/config/us.yaml +71 -0
- data/lib/holiday_calendar.rb +522 -0
- data/lib/modified_weekday.rb +135 -0
- data/lib/public_holiday.rb +173 -0
- data/lib/public_holiday_specification.rb +294 -0
- data/lib/religious_festival.rb +99 -0
- data/test/holiday_calendar_test.rb +664 -0
- data/test/modified_weekday_test.rb +201 -0
- data/test/public_holiday_specification_test.rb +254 -0
- data/test/public_holiday_test.rb +197 -0
- data/test/religious_festival_test.rb +25 -0
- data/test/test_helper.rb +14 -0
- data/test/units.rb +8 -0
- metadata +84 -0
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
|
4
|
+
|
5
|
+
class ReligiousFestival
|
6
|
+
|
7
|
+
#Get the date for easter sunday given the year.
|
8
|
+
def self.easter(year)
|
9
|
+
|
10
|
+
golden_number = (year % 19) + 1
|
11
|
+
year_of_calender_reform = 1752
|
12
|
+
|
13
|
+
if year <= year_of_calender_reform then
|
14
|
+
# Julian calendar
|
15
|
+
dominical_number = (year + (year / 4) + 5) % 7
|
16
|
+
paschal_full_moon = (3 - (11 * golden_number) - 7) % 30
|
17
|
+
else
|
18
|
+
# Gregorian calendar
|
19
|
+
dominical_number = (year + (year / 4) - (year / 100) + (year / 400)) % 7
|
20
|
+
solar_correction = (year - 1600) / 100 - (year - 1600) / 400
|
21
|
+
lunar_correction = (((year - 1400) / 100) * 8) / 25
|
22
|
+
paschal_full_moon = (3 - 11 * golden_number + solar_correction - lunar_correction) % 30
|
23
|
+
end
|
24
|
+
|
25
|
+
dominical_number += 7 until dominical_number > 0
|
26
|
+
paschal_full_moon += 30 until paschal_full_moon > 0
|
27
|
+
paschal_full_moon -= 1 if paschal_full_moon == 29 or (paschal_full_moon == 28 and golden_number > 11)
|
28
|
+
difference = (4 - paschal_full_moon - dominical_number) % 7
|
29
|
+
difference += 7 if difference < 0
|
30
|
+
easter_day = paschal_full_moon + difference + 1
|
31
|
+
|
32
|
+
if easter_day < 11 then
|
33
|
+
# Easter occurs in March.
|
34
|
+
return Date.new(year, 3, easter_day + 21)
|
35
|
+
else
|
36
|
+
# Easter occurs in April.
|
37
|
+
return Date.new(year, 4, easter_day - 10)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
|
43
|
+
|
44
|
+
# Determine the date of Good Friday for a given year.
|
45
|
+
#
|
46
|
+
def self.good_friday(some_year)
|
47
|
+
easter(some_year) - 2
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
|
52
|
+
# Determine the date of Palm Sunday for a given year.
|
53
|
+
#
|
54
|
+
def self.palm_sunday(some_year)
|
55
|
+
easter(some_year) - 7
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
|
60
|
+
# Determines the date of Ash Wednesday for a given year.
|
61
|
+
#
|
62
|
+
def self.ash_wednesday(some_year)
|
63
|
+
easter(some_year) - 46
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
|
68
|
+
# Determines the date of Ascension Day for a given year.
|
69
|
+
#
|
70
|
+
def self.ascension_day(some_year)
|
71
|
+
easter(some_year) + 39
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
|
76
|
+
# Determines the date of Pentecost for a given year.
|
77
|
+
#
|
78
|
+
def self.pentecost(some_year)
|
79
|
+
easter(some_year) + 49
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
def self.whit_sunday(some_year)
|
84
|
+
easter(some_year) + 49
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
def self.whit_monday(some_year)
|
89
|
+
easter(some_year) + 50
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
# determine the date of Easter Monday for a given year
|
94
|
+
#
|
95
|
+
def self.easter_monday(some_year)
|
96
|
+
easter(some_year) + 1
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
@@ -0,0 +1,664 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
require File.dirname(__FILE__) + '/../lib/holiday_calendar'
|
3
|
+
require File.dirname(__FILE__) + '/../lib/public_holiday_specification'
|
4
|
+
|
5
|
+
|
6
|
+
|
7
|
+
class HolidayCalendarTest < Test::Unit::TestCase
|
8
|
+
|
9
|
+
|
10
|
+
########### setup methods
|
11
|
+
|
12
|
+
def setup
|
13
|
+
# # create a working day schema with three public holidays, and weekends on Saturday, Sunday
|
14
|
+
@xmas = PublicHolidaySpecification.new(
|
15
|
+
:name => 'Christmas Day',
|
16
|
+
:years => :all,
|
17
|
+
:month => 12,
|
18
|
+
:day => 25,
|
19
|
+
:take_after => ['Saturday', 'Sunday'])
|
20
|
+
|
21
|
+
@box = PublicHolidaySpecification.new(
|
22
|
+
:name => 'Boxing Day',
|
23
|
+
:years => :all,
|
24
|
+
:month => 12,
|
25
|
+
:day => 26,
|
26
|
+
:take_after => [0,6])
|
27
|
+
|
28
|
+
@mayday = PublicHolidaySpecification.new(
|
29
|
+
:name => 'May Day',
|
30
|
+
:years => :all,
|
31
|
+
:month => 5,
|
32
|
+
:day => :first_monday,
|
33
|
+
:take_after => [:saturday, :sunday])
|
34
|
+
|
35
|
+
@tg = PublicHolidaySpecification.new(
|
36
|
+
:name => 'Thanksgiving Day',
|
37
|
+
:years => :all,
|
38
|
+
:month => 11,
|
39
|
+
:day => :last_thursday)
|
40
|
+
|
41
|
+
@summer = PublicHolidaySpecification.new(
|
42
|
+
:name => 'Summer Bank Holiday',
|
43
|
+
:years => :all,
|
44
|
+
:month => 8,
|
45
|
+
:day => :last_monday)
|
46
|
+
|
47
|
+
@spring = PublicHolidaySpecification.new(
|
48
|
+
:name => 'Spring Bank Holiday',
|
49
|
+
:years => :all,
|
50
|
+
:month => 5,
|
51
|
+
:day => :last_monday)
|
52
|
+
|
53
|
+
@newyear = PublicHolidaySpecification.new(
|
54
|
+
:name => "New Year's Day",
|
55
|
+
:years => :all,
|
56
|
+
:month => 1,
|
57
|
+
:day => 1,
|
58
|
+
:take_after => [:saturday, :sunday])
|
59
|
+
|
60
|
+
@olympic = PublicHolidaySpecification.new(
|
61
|
+
:name => 'Olympics Day',
|
62
|
+
:years => 2012,
|
63
|
+
:month => 8,
|
64
|
+
:day => 12,
|
65
|
+
:take_after => [:sunday],
|
66
|
+
:take_before => [:saturday])
|
67
|
+
|
68
|
+
@cal = HolidayCalendar.create(:uk, [0,6], [@xmas, @mayday, @tg, @box, @newyear, @spring, @olympic, @summer])
|
69
|
+
@num_public_holidays = @cal.size
|
70
|
+
|
71
|
+
@yaml_filename = File.dirname(__FILE__) + '/test.yaml'
|
72
|
+
end
|
73
|
+
|
74
|
+
def setup_yaml_contents
|
75
|
+
@yaml_contents = Hash.new
|
76
|
+
@yaml_contents['territory'] = 'uk'
|
77
|
+
@yaml_contents['weekend'] = ['saturday', 'sunday']
|
78
|
+
public_holidays = Hash.new
|
79
|
+
public_holidays["New Year's Day"] = {"month"=>1, "years"=>"all", "day"=>1}
|
80
|
+
public_holidays["Mayday"] = {"month"=>5, "years"=>"all", "day"=>"first_monday"}
|
81
|
+
public_holidays["Good Friday"] = {"class_method"=>"ReligiousFestival.good_friday", "years"=>"all"}
|
82
|
+
|
83
|
+
@yaml_contents['public_holidays'] = public_holidays
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
def save_yaml_contents
|
88
|
+
File.open(@yaml_filename, 'w') { |f| YAML.dump(@yaml_contents, f) }
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
|
93
|
+
############# tests for create method ####################
|
94
|
+
|
95
|
+
def test_holiday_object_created_from_array_gives_expected_results
|
96
|
+
# given a HolidayCalendar instantiated with the create method
|
97
|
+
# @cal
|
98
|
+
|
99
|
+
# when I query the object
|
100
|
+
# I should get expected results
|
101
|
+
assert_true @cal.weekend?(Date.new(2009, 8, 22)), 'Saturday 22 Aug 2009 not recognised as a weekend'
|
102
|
+
assert_true @cal.weekend?(Date.new(2009, 8, 23)), 'Sunday 23 Aug 2009 not recognised as a weekend'
|
103
|
+
assert_false @cal.working_day?(Date.new(2009, 8, 22)), 'Saturday 22 Aug 2009 erroneously recognised as a working day'
|
104
|
+
assert_true @cal.public_holiday?(Date.new(2009, 8, 31)), 'August Bank holiday not recognised as a public holiday'
|
105
|
+
assert_false @cal.working_day?(Date.new(2009, 8, 31)), 'August Bank holiday erroneously recognised as a working day'
|
106
|
+
assert_true @cal.public_holiday?(Date.new(2012, 8, 13)), 'August 13 2012 (Olympics day carried forward from 12th) not recognised as a public holiday'
|
107
|
+
assert_false @cal.public_holiday?(Date.new(2011, 8, 13)), 'August 12 2011 erroneously recognised as a public holiday'
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
|
112
|
+
def test_list_for_year_produces_exected_results
|
113
|
+
# given @call setup as standard
|
114
|
+
# when I call list_for_year
|
115
|
+
# I should get an array of strings representing the holidays in date order
|
116
|
+
|
117
|
+
expected = Array.new
|
118
|
+
expected << "Thu 01 Jan 2009 : New Year's Day"
|
119
|
+
expected << "Mon 04 May 2009 : May Day"
|
120
|
+
expected << "Mon 25 May 2009 : Spring Bank Holiday"
|
121
|
+
expected << "Mon 31 Aug 2009 : Summer Bank Holiday"
|
122
|
+
expected << "Thu 26 Nov 2009 : Thanksgiving Day"
|
123
|
+
expected << "Fri 25 Dec 2009 : Christmas Day"
|
124
|
+
expected << "Mon 28 Dec 2009 : Boxing Day (carried forward from Sat 26 Dec 2009)"
|
125
|
+
|
126
|
+
assert_equal expected, @cal.list_for_year(2009)
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
def test_holiday_calendar_created_with_day_names_gives_expected_results
|
131
|
+
# given a HolidayCalendar created with weekends specified as day names
|
132
|
+
cal = HolidayCalendar.create(:test, ['Thursday', 'Friday'], [@xmas, @box])
|
133
|
+
|
134
|
+
# when I read the weekend day numbers, they should be 4 and 5
|
135
|
+
assert_equal [4,5], cal.weekend
|
136
|
+
end
|
137
|
+
|
138
|
+
|
139
|
+
def test_holiday_calendar_created_with_invalid_objects_throws_an_exception
|
140
|
+
err = assert_raise ArgumentError do
|
141
|
+
cal = HolidayCalendar.create('string', ['x', 'y'], ['a', 'b', 'c'])
|
142
|
+
end
|
143
|
+
assert_equal 'territory must be specified as symbol in HolidayCalendar.create', err.message
|
144
|
+
|
145
|
+
err = assert_raise ArgumentError do
|
146
|
+
cal = HolidayCalendar.create(:test, [45.3, 'y'], ['a', 'b', 'c'])
|
147
|
+
end
|
148
|
+
assert_equal 'Invalid weekend array passsed to HolidayCalendar.create: each day must be day number in range 0-6 or day name', err.message
|
149
|
+
|
150
|
+
err = assert_raise ArgumentError do
|
151
|
+
cal = HolidayCalendar.create(:test, ['Saturday', 6], ['a', 'b', 'c'])
|
152
|
+
end
|
153
|
+
assert_equal 'public holidays must be an array of PublicHolidaySpecification objects in HolidayCalendar.create', err.message
|
154
|
+
end
|
155
|
+
|
156
|
+
|
157
|
+
|
158
|
+
|
159
|
+
############### tests for load_file method
|
160
|
+
|
161
|
+
def test_exception_thrown_when_no_territory_setting_supplied_in_yaml_file
|
162
|
+
# given a yaml file with no territory section
|
163
|
+
setup_yaml_contents
|
164
|
+
@yaml_contents.delete('territory')
|
165
|
+
save_yaml_contents
|
166
|
+
|
167
|
+
# when I try to instantiate a HolidayCalendar from the file
|
168
|
+
# I should get an exception
|
169
|
+
err = assert_raise ArgumentError do
|
170
|
+
cal = HolidayCalendar.load_file(@yaml_filename)
|
171
|
+
end
|
172
|
+
assert_equal "YAML file #{@yaml_filename} does not have a 'territory' setting", err.message
|
173
|
+
end
|
174
|
+
|
175
|
+
|
176
|
+
def test_exception_thrown_when_no_weekend_setting_supplied_in_yaml_file
|
177
|
+
# given a yaml file with no weekend section
|
178
|
+
setup_yaml_contents
|
179
|
+
@yaml_contents.delete('weekend')
|
180
|
+
save_yaml_contents
|
181
|
+
|
182
|
+
# when I try to instantiate a HolidayCalendar from the file
|
183
|
+
# I should get an exception
|
184
|
+
err = assert_raise ArgumentError do
|
185
|
+
cal = HolidayCalendar.load_file(@yaml_filename)
|
186
|
+
end
|
187
|
+
assert_equal "YAML file #{@yaml_filename} does not have a 'weekend' setting", err.message
|
188
|
+
end
|
189
|
+
|
190
|
+
def test_exception_thrown_when_no_weekend_setting_in_yaml_file_is_not_an_array
|
191
|
+
# given a yaml file with no weekend section
|
192
|
+
setup_yaml_contents
|
193
|
+
@yaml_contents['weekend'] = "saturday, sunday"
|
194
|
+
save_yaml_contents
|
195
|
+
|
196
|
+
# when I try to instantiate a HolidayCalendar from the file
|
197
|
+
# I should get an exception
|
198
|
+
err = assert_raise ArgumentError do
|
199
|
+
cal = HolidayCalendar.load_file(@yaml_filename)
|
200
|
+
end
|
201
|
+
assert_equal "Invalid YAML file element 'weekend' - must be an Array, is String", err.message
|
202
|
+
end
|
203
|
+
|
204
|
+
|
205
|
+
def test_exception_thrown_when_invalid_day_name_given_as_weekend_in_yaml_file
|
206
|
+
# given a yaml file with an invalid weekend section
|
207
|
+
setup_yaml_contents
|
208
|
+
@yaml_contents['weekend'] = ['subbota', 'voskresseniye']
|
209
|
+
save_yaml_contents
|
210
|
+
|
211
|
+
# when I try to instantiate a HolidayCalendar from the file
|
212
|
+
# I should get an exception
|
213
|
+
err = assert_raise ArgumentError do
|
214
|
+
cal = HolidayCalendar.load_file(@yaml_filename)
|
215
|
+
end
|
216
|
+
assert_equal "Invalid day specified as weekend: subbota", err.message
|
217
|
+
end
|
218
|
+
|
219
|
+
|
220
|
+
def test_weekend_day_names_are_translated_into_correct_day_numbers
|
221
|
+
# given a yaml file with no weekend section
|
222
|
+
setup_yaml_contents
|
223
|
+
save_yaml_contents
|
224
|
+
|
225
|
+
# when I instantiate a HolidayCalendar from a yaml file
|
226
|
+
cal = HolidayCalendar.load_file(@yaml_filename)
|
227
|
+
|
228
|
+
# the weekend should be setup correctly
|
229
|
+
assert_equal [6,0], cal.weekend
|
230
|
+
end
|
231
|
+
|
232
|
+
|
233
|
+
def test_exception_thrown_when_no_public_holiday_setting_supplied_in_yaml_file
|
234
|
+
# given a yaml file with no weekend section
|
235
|
+
setup_yaml_contents
|
236
|
+
@yaml_contents.delete('public_holidays')
|
237
|
+
save_yaml_contents
|
238
|
+
|
239
|
+
# when I try to instantiate a HolidayCalendar from the file
|
240
|
+
# I should get an exception
|
241
|
+
err = assert_raise ArgumentError do
|
242
|
+
cal = HolidayCalendar.load_file(@yaml_filename)
|
243
|
+
end
|
244
|
+
assert_equal "YAML file #{@yaml_filename} does not have a 'public_holidays' setting", err.message
|
245
|
+
end
|
246
|
+
|
247
|
+
|
248
|
+
def test_exception_thrown_when_no_public_holiday_setting_in_yaml_file_is_not_an_array
|
249
|
+
# given a yaml file with no weekend section
|
250
|
+
setup_yaml_contents
|
251
|
+
@yaml_contents['public_holidays'] = "Good Friday, Easter Monday"
|
252
|
+
save_yaml_contents
|
253
|
+
|
254
|
+
# when I try to instantiate a HolidayCalendar from the file
|
255
|
+
# I should get an exception
|
256
|
+
err = assert_raise ArgumentError do
|
257
|
+
cal = HolidayCalendar.load_file(@yaml_filename)
|
258
|
+
end
|
259
|
+
assert_equal "Invalid YAML file element 'public_holidays' - must be an Hash, is String", err.message
|
260
|
+
end
|
261
|
+
|
262
|
+
|
263
|
+
def test_that_holidays_are_setup_as_expected_from_yaml_file
|
264
|
+
# given a yaml file
|
265
|
+
setup_yaml_contents
|
266
|
+
save_yaml_contents
|
267
|
+
|
268
|
+
# when I instantiate a Holiday Calendar from it
|
269
|
+
cal = HolidayCalendar.load_file(@yaml_filename)
|
270
|
+
# Then the first monday in may should be a public holiday
|
271
|
+
assert_true cal.public_holiday?(Date.new(2009, 5, 4))
|
272
|
+
|
273
|
+
# new Year's day should be a holiday
|
274
|
+
assert_true cal.public_holiday?(Date.new(2009, 1, 1))
|
275
|
+
|
276
|
+
# Good Friday should be a public holiday
|
277
|
+
assert_true cal.public_holiday?(Date.new(2009, 4, 10))
|
278
|
+
|
279
|
+
|
280
|
+
# saturdays and sundays should be weekends
|
281
|
+
assert_true cal.weekend?(Date.new(2009, 8, 15))
|
282
|
+
assert_true cal.weekend?(Date.new(2009, 8, 16))
|
283
|
+
|
284
|
+
# evrything else should be a working day
|
285
|
+
assert_true cal.working_day?(Date.new(2009, 8, 13))
|
286
|
+
|
287
|
+
end
|
288
|
+
|
289
|
+
|
290
|
+
|
291
|
+
################## test load method
|
292
|
+
|
293
|
+
|
294
|
+
def test_loading_from_french_std_config_gives_expected_results
|
295
|
+
|
296
|
+
# given a holiday calendar loaded from a standard config for france
|
297
|
+
cal = HolidayCalendar.load(:fr)
|
298
|
+
|
299
|
+
# when I test french holiday dates, then they should be holidays
|
300
|
+
nyd = Date.new(2010, 1, 1)
|
301
|
+
assert_true cal.public_holiday?(nyd)
|
302
|
+
assert_equal "Jour de l'An", cal.holiday_name(nyd)
|
303
|
+
|
304
|
+
em = Date.new(2010, 4, 5)
|
305
|
+
assert_true cal.public_holiday?(em)
|
306
|
+
assert_equal 'lundi de Pâques', cal.holiday_name(em)
|
307
|
+
|
308
|
+
ld = Date.new(2009, 5, 1)
|
309
|
+
assert_true cal.public_holiday?(ld)
|
310
|
+
assert_equal 'Fête du Travail', cal.holiday_name(ld)
|
311
|
+
|
312
|
+
ved = Date.new(2009, 5, 8)
|
313
|
+
assert_true cal.public_holiday?(ved)
|
314
|
+
assert_equal 'Fête de la Victoire 1945', cal.holiday_name(ved)
|
315
|
+
|
316
|
+
ad = Date.new(2009, 5, 21)
|
317
|
+
assert_true cal.public_holiday?(ad)
|
318
|
+
assert_equal 'Ascension catholique', cal.holiday_name(ad)
|
319
|
+
|
320
|
+
wm = Date.new(2009, 6, 1)
|
321
|
+
assert_true cal.public_holiday?(wm)
|
322
|
+
assert_equal 'Lundi de Pentecôte', cal.holiday_name(wm)
|
323
|
+
|
324
|
+
fn = Date.new(2009, 7, 14)
|
325
|
+
assert_true cal.public_holiday?(fn)
|
326
|
+
assert_equal 'Fête nationale', cal.holiday_name(fn)
|
327
|
+
|
328
|
+
ts = Date.new(2010, 11, 1)
|
329
|
+
assert_true cal.public_holiday?(ts)
|
330
|
+
assert_equal 'Toussaint', cal.holiday_name(ts)
|
331
|
+
|
332
|
+
arm = Date.new(2009, 11, 11)
|
333
|
+
assert_true cal.public_holiday?(arm)
|
334
|
+
assert_equal "Armistice", cal.holiday_name(arm)
|
335
|
+
|
336
|
+
xmas = Date.new(2009, 12, 25)
|
337
|
+
assert_true cal.public_holiday?(xmas)
|
338
|
+
assert_equal 'Noel', cal.holiday_name(xmas)
|
339
|
+
end
|
340
|
+
|
341
|
+
|
342
|
+
def test_loading_from_uk_std_config_gives_expected_results
|
343
|
+
# given a holiday calendar loaded from a standard config for france
|
344
|
+
cal = HolidayCalendar.load(:uk)
|
345
|
+
|
346
|
+
# when I test UK holiday dates, then they should be holidays
|
347
|
+
assert_true cal.public_holiday?(Date.new(2010, 1, 1))
|
348
|
+
assert_equal "New Year's Day", cal.holiday_name(Date.new(2010, 1, 1))
|
349
|
+
|
350
|
+
assert_true cal.public_holiday?(Date.new(2010, 4, 2))
|
351
|
+
assert_equal "Good Friday", cal.holiday_name(Date.new(2010, 4, 2))
|
352
|
+
|
353
|
+
assert_true cal.public_holiday?(Date.new(2010, 4, 5))
|
354
|
+
assert_equal "Easter Monday", cal.holiday_name(Date.new(2010, 4, 5))
|
355
|
+
|
356
|
+
assert_true cal.public_holiday?(Date.new(2010, 5, 3))
|
357
|
+
assert_equal 'May Day', cal.holiday_name(Date.new(2010, 5, 3))
|
358
|
+
|
359
|
+
assert_true cal.public_holiday?(Date.new(2010, 5, 31))
|
360
|
+
assert_equal "Spring Bank Holiday", cal.holiday_name(Date.new(2010, 5, 31))
|
361
|
+
|
362
|
+
assert_true cal.public_holiday?(Date.new(2010, 8, 30))
|
363
|
+
assert_equal "Summer Bank Holiday", cal.holiday_name(Date.new(2010, 8, 30))
|
364
|
+
|
365
|
+
assert_true cal.public_holiday?(Date.new(2010, 12, 27))
|
366
|
+
assert_equal "Christmas Day (carried forward from Sat 25 Dec 2010)", cal.holiday_name(Date.new(2010, 12, 27))
|
367
|
+
|
368
|
+
assert_true cal.public_holiday?(Date.new(2010, 12, 28))
|
369
|
+
assert_equal "Boxing Day (carried forward from Sun 26 Dec 2010)", cal.holiday_name(Date.new(2010, 12, 28))
|
370
|
+
end
|
371
|
+
|
372
|
+
|
373
|
+
def test_take_before_when_take_before_means_last_day_of_previous_year
|
374
|
+
# given a holiday of January 1st and is taken before if falling on a Saturday
|
375
|
+
phs = PublicHolidaySpecification.new(:name => 'test', :years => :all, :day => 1, :month => 1, :take_before => [:saturday])
|
376
|
+
cal = HolidayCalendar.create(:us, [0,6], [phs])
|
377
|
+
|
378
|
+
# when I test to see if Friday 31st December 2010 is a holiday (1st Jan 2011 is a saturday)
|
379
|
+
# it should say yes
|
380
|
+
assert_true cal.public_holiday?(Date.new(2010, 12,31))
|
381
|
+
end
|
382
|
+
|
383
|
+
|
384
|
+
def test_loading_us_calendar_for_2009_gives_expected_results
|
385
|
+
# given a holiday calendar loaded from the standard config for the US
|
386
|
+
cal = HolidayCalendar.load(:us)
|
387
|
+
|
388
|
+
# New Year's day dates for years 2009 - 2013
|
389
|
+
nyd_dates = [ [2009,1,1], [2010,1,1], [2010,12,31], [2012,1,2], [2013,1,1] ]
|
390
|
+
assert_holidays nyd_dates, cal, "New Year's Day"
|
391
|
+
|
392
|
+
mlk_dates = [ [2009,1,19], [2010,1,18], [2011,1,17], [2012,1,16], [2013,1,21 ]]
|
393
|
+
assert_holidays mlk_dates, cal, 'Birthday of Martin Luther King, Jr.'
|
394
|
+
|
395
|
+
wb_dates = [ [2009,2,16], [2010,2,15], [2011,2,21], [2012,2,20], [2013,2,18] ]
|
396
|
+
assert_holidays wb_dates, cal, "Washington's Birthday"
|
397
|
+
|
398
|
+
md_dates = [ [2009,5,25], [2010,5,31], [2011,5,30], [2012,5,28], [2013,5,27] ]
|
399
|
+
assert_holidays md_dates, cal, 'Memorial Day'
|
400
|
+
|
401
|
+
id_dates = [ [2009,7,3], [2010,7,5], [2011,7,4], [2012,7,4], [2013,7,4] ]
|
402
|
+
assert_holidays id_dates, cal, 'Independence Day'
|
403
|
+
|
404
|
+
ld_dates = [ [2009,9,7], [2010,9,6], [2011,9,5], [2012,9,3], [2013,9,2] ]
|
405
|
+
assert_holidays ld_dates, cal, 'Labor Day'
|
406
|
+
|
407
|
+
cd_dates = [ [2009,10,12], [2010,10,11], [2011,10,10], [2012,10,8], [2013,10,14] ]
|
408
|
+
assert_holidays cd_dates, cal, 'Columbus Day'
|
409
|
+
|
410
|
+
vd_dates = [ [2009,11,11], [2010,11,11], [2011,11,11], [2012,11,12], [2013,11,11] ]
|
411
|
+
assert_holidays vd_dates, cal, "Veterans' Day"
|
412
|
+
|
413
|
+
tgd_dates = [ [2009,11,26], [2010,11,25], [2011,11,24], [2012,11,22], [2013,11,28] ]
|
414
|
+
assert_holidays tgd_dates, cal, "Thanksgiving Day"
|
415
|
+
|
416
|
+
xmas_dates = [ [2009,12,25], [2010,12,24], [2011,12,26], [2012,12,25], [2013,12,25] ]
|
417
|
+
assert_holidays xmas_dates, cal, "Christmas Day"
|
418
|
+
end
|
419
|
+
|
420
|
+
# [ [2009], [2010], [2011], [2012], [2013] ]
|
421
|
+
|
422
|
+
|
423
|
+
def assert_holidays(holiday_dates, cal, holiday_name)
|
424
|
+
holiday_dates.each do |holiday_date|
|
425
|
+
date = arr2date(holiday_date)
|
426
|
+
assert_true cal.public_holiday?(date), "#{date} not recognised as #{holiday_name}"
|
427
|
+
assert_match /^#{holiday_name}/, cal.holiday_name(date)
|
428
|
+
end
|
429
|
+
end
|
430
|
+
|
431
|
+
|
432
|
+
def arr2date(array)
|
433
|
+
Date.new(array[0], array[1], array[2])
|
434
|
+
end
|
435
|
+
|
436
|
+
|
437
|
+
def test_exception_raised_if_filename_specifies_non_existing_file_in_yaml_mode
|
438
|
+
err = assert_raise ArgumentError do
|
439
|
+
cal = HolidayCalendar.load_file('i_do_not_exist.yaml')
|
440
|
+
end
|
441
|
+
assert_equal 'The filename specified in HolidayCalender.new cannot be found: i_do_not_exist.yaml', err.message
|
442
|
+
end
|
443
|
+
|
444
|
+
|
445
|
+
|
446
|
+
def test_adding_one_extra_holiday_works_as_expected
|
447
|
+
# given a Holiday Calendar which has been queried for 2009 and 2012
|
448
|
+
assert_true @cal.public_holiday?(Date.new(2009, 12, 25))
|
449
|
+
assert_false @cal.public_holiday?(Date.new(2012, 2, 1))
|
450
|
+
|
451
|
+
# when I add an extra holiday
|
452
|
+
@cal << PublicHolidaySpecification.new(:name => 'My Birthday', :years => :all, :month => 8, :day => 13)
|
453
|
+
|
454
|
+
# then that day should be a holiday in years that have previously been queried and other years
|
455
|
+
assert_true @cal.public_holiday?(Date.new(2009, 8, 13))
|
456
|
+
assert_true @cal.public_holiday?(Date.new(2010, 8, 13))
|
457
|
+
assert_true @cal.public_holiday?(Date.new(2012, 8, 13))
|
458
|
+
end
|
459
|
+
|
460
|
+
|
461
|
+
def test_adding_an_array_of_extra_holidays_works_as_exptected
|
462
|
+
# given a Holiday Calendar which has been queried for 2009 and 2012
|
463
|
+
assert_true @cal.public_holiday?(Date.new(2009, 12, 25))
|
464
|
+
assert_false @cal.public_holiday?(Date.new(2012, 2, 1))
|
465
|
+
|
466
|
+
# when I add an array of extra holidays
|
467
|
+
ph1 = PublicHolidaySpecification.new(:name => 'My Birthday', :years => :all, :month => 8, :day => 13)
|
468
|
+
ph2 = PublicHolidaySpecification.new(:name => "Tony's Birthday", :years => :all, :month => 5, :day => 17, :take_after => [0,6])
|
469
|
+
ph3 = PublicHolidaySpecification.new(:name => "Charles' Birthday", :years => :all, :month => 4, :day => 3)
|
470
|
+
@cal << [ph1, ph2, ph3]
|
471
|
+
|
472
|
+
# then that those days should be a holiday in years that have previously been queried and other years
|
473
|
+
assert_true @cal.public_holiday?(Date.new(2009, 8, 13))
|
474
|
+
assert_true @cal.public_holiday?(Date.new(2010, 8, 13))
|
475
|
+
assert_true @cal.public_holiday?(Date.new(2012, 8, 13))
|
476
|
+
assert_true @cal.public_holiday?(Date.new(2010, 5, 17))
|
477
|
+
assert_true @cal.public_holiday?(Date.new(2012, 5, 17))
|
478
|
+
assert_true @cal.public_holiday?(Date.new(2009, 4, 3))
|
479
|
+
assert_true @cal.public_holiday?(Date.new(2012, 4, 3))
|
480
|
+
|
481
|
+
# and the pre-existing holidays should still be recognised as such
|
482
|
+
assert_true @cal.public_holiday?(Date.new(2011, 12, 26))
|
483
|
+
|
484
|
+
end
|
485
|
+
|
486
|
+
|
487
|
+
def test_adding_an_object_which_isnt_a_public_holiday_specification_throws_an_exception
|
488
|
+
err = assert_raise ArgumentError do
|
489
|
+
@cal << {:key1=> :val1, :key2 => :val2}
|
490
|
+
end
|
491
|
+
assert_equal(
|
492
|
+
'you must pass a PublicHolidaySpecification or an array of PublicHolidaySpecification objects to << method of HolidayCalendar',
|
493
|
+
err.message)
|
494
|
+
end
|
495
|
+
|
496
|
+
|
497
|
+
def test_adding_an_array_of_objects_that_arent_all_public_holiday_specications_throws_an_exception
|
498
|
+
err = assert_raise ArgumentError do
|
499
|
+
@cal << [@tg, @mayday, 'another Holiday', @xmas]
|
500
|
+
end
|
501
|
+
assert_equal(
|
502
|
+
'you must pass a PublicHolidaySpecification or an array of PublicHolidaySpecification objects to << method of HolidayCalendar',
|
503
|
+
err.message)
|
504
|
+
end
|
505
|
+
|
506
|
+
|
507
|
+
|
508
|
+
def test_deleting_a_holiday_works_as_expected
|
509
|
+
# given the standard calendar which reports boxing day and Christmas day as a holiday and has seven public holidays
|
510
|
+
assert_true @cal.public_holiday?(Date.new(2009, 12, 28)), '28 Dec 2009 (boxing Day carried forward) is not reported as a holiday'
|
511
|
+
assert_true @cal.public_holiday?(Date.new(2011, 12, 26))
|
512
|
+
assert_true @cal.public_holiday?(Date.new(2009, 12, 25))
|
513
|
+
assert_equal @num_public_holidays, @cal.size
|
514
|
+
|
515
|
+
# when I delete boxing day
|
516
|
+
result = @cal.delete('Boxing Day')
|
517
|
+
|
518
|
+
# then result should be true indicating that boxing day has been found
|
519
|
+
# the number of public holidays should be decreased by 1
|
520
|
+
# boxing day should no longer be a holiday but other holidays should remain
|
521
|
+
assert_true result
|
522
|
+
assert_equal @num_public_holidays - 1, @cal.size
|
523
|
+
assert_false @cal.public_holiday?(Date.new(2009, 12, 28)), '28 Dec 2009 (boxing Day carried forward) is reported as a holiday after deletion'
|
524
|
+
assert_false @cal.public_holiday?(Date.new(2012, 12, 26)), '26 Dec 2011 (boxing Day ) is reported as a holiday after deletion'
|
525
|
+
assert_true @cal.public_holiday?(Date.new(2009, 12, 25)), 'Christmas day 2009 is not reported as a holiday after deletion of boxing day'
|
526
|
+
end
|
527
|
+
|
528
|
+
|
529
|
+
def test_attempting_to_delete_a_non_existent_public_holiday_results_in_false
|
530
|
+
# given the standard calendar or 8 public holidays
|
531
|
+
assert_equal @num_public_holidays, @cal.size
|
532
|
+
|
533
|
+
# when I delete a holiday that doesn't exist
|
534
|
+
result = @cal.delete('My Birthday')
|
535
|
+
|
536
|
+
# the result should be false and the number of holidays should remain unchanged
|
537
|
+
assert_false result
|
538
|
+
assert_equal @num_public_holidays, @cal.size
|
539
|
+
end
|
540
|
+
|
541
|
+
|
542
|
+
|
543
|
+
|
544
|
+
|
545
|
+
|
546
|
+
|
547
|
+
|
548
|
+
|
549
|
+
|
550
|
+
|
551
|
+
|
552
|
+
|
553
|
+
|
554
|
+
|
555
|
+
|
556
|
+
|
557
|
+
|
558
|
+
|
559
|
+
def test_is_weekend_returns_true_for_weekends
|
560
|
+
# given a working day schema where saturdays and sundays are weekends
|
561
|
+
# when I ask whether a saturday is a weekend,I shoudl get true
|
562
|
+
assert_true @cal.weekend?(Date.new(2009, 8, 15))
|
563
|
+
assert_true @cal.weekend?(Date.new(2009, 8, 16))
|
564
|
+
|
565
|
+
assert_false @cal.weekend?(Date.new(2009, 8, 14))
|
566
|
+
assert_false @cal.weekend?(Date.new(2009, 8, 14))
|
567
|
+
end
|
568
|
+
|
569
|
+
|
570
|
+
def test_public_holidays_are_recognised
|
571
|
+
# given a working day schema with 8 public holidays
|
572
|
+
# when I ask whether Christmas day is a public holiday, it should give true
|
573
|
+
assert_true @cal.public_holiday?(Date.new(2007, 12, 25))
|
574
|
+
|
575
|
+
# when I ask whether or not the 28th is a public holiday, it should give false
|
576
|
+
assert_false @cal.public_holiday?(Date.new(2007, 12, 28))
|
577
|
+
|
578
|
+
# when I ask whether Monday 7th May 2012 is a public holiday, it should reply true (it's the first monday)
|
579
|
+
assert_true @cal.public_holiday?(Date.new(2012, 5, 7))
|
580
|
+
|
581
|
+
# when I ask if the next day is a public holiday it should say false
|
582
|
+
assert_false @cal.public_holiday?(Date.new(2012, 5, 8))
|
583
|
+
|
584
|
+
# when I ask if 26th November 2009 is a holiday, it should say true (it's the last thursday)
|
585
|
+
assert_true @cal.public_holiday?(Date.new(2009, 11, 26))
|
586
|
+
|
587
|
+
# but false for the next day
|
588
|
+
assert_false @cal.public_holiday?(Date.new(2009, 11, 27))
|
589
|
+
end
|
590
|
+
|
591
|
+
|
592
|
+
|
593
|
+
def test_working_day_returns_false_if_its_a_weekend
|
594
|
+
assert_false @cal.working_day?(Date.new(2009, 8, 15)) # Saturday
|
595
|
+
assert_false @cal.working_day?(Date.new(2009, 8, 16)) # Sunday
|
596
|
+
end
|
597
|
+
|
598
|
+
|
599
|
+
def test_exception_raised_if_start_date_passed_to_count_working_days_between_not_before_end_date
|
600
|
+
err = assert_raise ArgumentError do
|
601
|
+
@cal.count_working_days_between(Date.new(2009, 12, 25), Date.new(2009, 12, 24))
|
602
|
+
end
|
603
|
+
assert_equal "start_date passed to HolidayCalendar.count_days_between() is not before end_date", err.message
|
604
|
+
end
|
605
|
+
|
606
|
+
|
607
|
+
|
608
|
+
def test_count_working_days_between_two_dates
|
609
|
+
# given two dates Wed 23rd Dec and WEdnesday 30th Dec 2009
|
610
|
+
start_date = Date.new(2009, 12, 23)
|
611
|
+
end_date = Date.new(2009, 12, 30)
|
612
|
+
|
613
|
+
# when I count the working days betwen them, it should give me 4 (Christmas day, Boxing Day and Saturday and Sunday are not working days)
|
614
|
+
assert_equal 3, @cal.count_working_days_between(start_date, end_date)
|
615
|
+
end
|
616
|
+
|
617
|
+
|
618
|
+
|
619
|
+
def test_counting_forward_days_with_no_weekend
|
620
|
+
start_date = Date.new(2009, 8, 10) # monday
|
621
|
+
target_end_date = Date.new(2009, 8, 14) # friday
|
622
|
+
|
623
|
+
assert_equal target_end_date, @cal.working_days_after(start_date, 4)
|
624
|
+
end
|
625
|
+
|
626
|
+
|
627
|
+
def test_counting_forward_days_with_weekend
|
628
|
+
start_date = Date.new(2009, 8, 10) # monday
|
629
|
+
target_end_date = Date.new(2009, 8, 19) # friday
|
630
|
+
|
631
|
+
assert_equal target_end_date, @cal.working_days_after(start_date, 7)
|
632
|
+
end
|
633
|
+
|
634
|
+
|
635
|
+
|
636
|
+
def test_counting_backward_days_with_no_weekend
|
637
|
+
start_date = Date.new(2009, 8, 14) # friday
|
638
|
+
target_end_date = Date.new(2009, 8, 10) # monday
|
639
|
+
|
640
|
+
actual_end_date = @cal.working_days_before(start_date, 4)
|
641
|
+
assert_equal target_end_date, actual_end_date, "Target end date: #{target_end_date}, actual: #{actual_end_date}"
|
642
|
+
end
|
643
|
+
|
644
|
+
|
645
|
+
def test_counting_forward_with_weekend_and_holiday
|
646
|
+
start_date = Date.new(2009, 4, 28) # wed 29th apr
|
647
|
+
target_end_date = Date.new(2009, 5, 6) # wed 6th may (monday 4th is holiday)
|
648
|
+
|
649
|
+
actual_end_date = @cal.working_days_after(start_date, 5)
|
650
|
+
assert_equal target_end_date, actual_end_date, "Target end date: #{target_end_date}, actual: #{actual_end_date}"
|
651
|
+
end
|
652
|
+
|
653
|
+
|
654
|
+
|
655
|
+
def test_holiday_name_returns_expected_holiday_name
|
656
|
+
assert_equal 'Christmas Day', @cal.holiday_name(Date.new(2009, 12, 25))
|
657
|
+
assert_equal 'Boxing Day (carried forward from Sat 26 Dec 2009)', @cal.holiday_name(Date.new(2009, 12, 28))
|
658
|
+
assert_equal 'Boxing Day', @cal.holiday_name(Date.new(2009, 12, 28), false)
|
659
|
+
assert_nil @cal.holiday_name(Date.new(2008, 8, 21))
|
660
|
+
end
|
661
|
+
|
662
|
+
end
|
663
|
+
|
664
|
+
|