stephenrichards-holiday_calendar 1.0.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+