Bug 19532: (follow-up) aria-hidden attr on OPAC, and more
[koha.git] / t / db_dependent / Calendar.t
1 #!/usr/bin/perl
2
3 # This file is part of Koha.
4 #
5 # Koha is free software; you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # Koha is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with Koha; if not, see <http://www.gnu.org/licenses>.
17
18 use Modern::Perl;
19
20 use Test::More tests => 6;
21 use Time::Fake;
22
23 use t::lib::Mocks;
24 use t::lib::TestBuilder;
25
26 use DateTime;
27 use Koha::Caches;
28 use Koha::DateUtils qw( dt_from_string );
29
30 use_ok('Koha::Calendar');
31
32 my $schema  = Koha::Database->new->schema;
33 $schema->storage->txn_begin;
34
35 my $today = dt_from_string();
36 my $holiday_dt = $today->clone;
37 $holiday_dt->add(days => 3);
38
39 Koha::Caches->get_instance()->flush_all();
40
41 my $builder = t::lib::TestBuilder->new();
42 my $library = $builder->build_object({ class => 'Koha::Libraries' });
43 my $holiday = $builder->build(
44     {
45         source => 'SpecialHoliday',
46         value  => {
47             branchcode  => $library->branchcode,
48             day         => $holiday_dt->day,
49             month       => $holiday_dt->month,
50             year        => $holiday_dt->year,
51             title       => 'My holiday',
52             isexception => 0
53         },
54     }
55 );
56
57 my $calendar = Koha::Calendar->new( branchcode => $library->branchcode, days_mode => 'Calendar' );
58
59 subtest 'days_forward' => sub {
60
61     plan tests => 4;
62     my $forwarded_dt = $calendar->days_forward( $today, 2 );
63     my $expected = $today->clone->add( days => 2 );
64     is( $forwarded_dt->ymd, $expected->ymd, 'With no holiday on the perioddays_forward should add 2 days' );
65
66     $forwarded_dt = $calendar->days_forward( $today, 5 );
67     $expected = $today->clone->add( days => 6 );
68     is( $forwarded_dt->ymd, $expected->ymd, 'With holiday on the perioddays_forward should add 5 days + 1 day for holiday'
69     );
70
71     $forwarded_dt = $calendar->days_forward( $today, 0 );
72     is( $forwarded_dt->ymd, $today->ymd, '0 day should return start dt' );
73
74     $forwarded_dt = $calendar->days_forward( $today, -2 );
75     is( $forwarded_dt->ymd, $today->ymd, 'negative day should return start dt' );
76 };
77
78 subtest 'crossing_DST' => sub {
79
80     plan tests => 3;
81
82     my $tz = DateTime::TimeZone->new( name => 'America/New_York' );
83     my $start_date = dt_from_string( "2016-03-09 02:29:00", undef, $tz );
84     my $end_date   = dt_from_string( "2017-01-01 00:00:00", undef, $tz );
85     my $days_between = $calendar->days_between( $start_date, $end_date );
86     is( $days_between->delta_days, 298, "Days calculated correctly" );
87     $days_between = $calendar->days_between( $end_date, $start_date );
88     is( $days_between->delta_days, 298, "Swapping returns the same" );
89     my $hours_between = $calendar->hours_between( $start_date, $end_date );
90     is(
91         $hours_between->delta_minutes,
92         298 * 24 * 60 - 149,
93         "Hours (in minutes) calculated correctly"
94     );
95 };
96
97 subtest 'hours_between | days_between' => sub {
98
99     plan tests => 2;
100
101     #    November 2019
102     # Su Mo Tu We Th Fr Sa
103     #                 1  2
104     #  3  4 *5* 6  7  8  9
105     # 10 11 12 13 14 15 16
106     # 17 18 19 20 21 22 23
107     # 24 25 26 27 28 29 30
108
109     my $now    = dt_from_string('2019-11-05 12:34:56'); # Today is 2019 Nov 5th
110     my $nov_6  = dt_from_string('2019-11-06 12:34:56');
111     my $nov_7  = dt_from_string('2019-11-07 12:34:56');
112     my $nov_12 = dt_from_string('2019-11-12 12:34:56');
113     my $nov_13 = dt_from_string('2019-11-13 12:34:56');
114     my $nov_15 = dt_from_string('2019-11-15 12:34:56');
115     Time::Fake->offset($now->epoch);
116
117     subtest 'No holiday' => sub {
118
119         plan tests => 2;
120
121         my $library = $builder->build_object({ class => 'Koha::Libraries' });
122         my $calendar = Koha::Calendar->new( branchcode => $library->branchcode );
123
124         subtest 'Same hours' => sub {
125
126             plan tests => 8;
127
128             # Between 5th and 6th
129             my $diff_hours = $calendar->hours_between( $now, $nov_6 )->hours;
130             is( $diff_hours, 1 * 24, 'hours: 1 day, no holiday' );
131             my $diff_days = $calendar->days_between( $now, $nov_6 )->delta_days;
132             is( $diff_days, 1, 'days: 1 day, no holiday' );
133
134             # Between 5th and 7th
135             $diff_hours = $calendar->hours_between( $now, $nov_7 )->hours;
136             is( $diff_hours, 2 * 24, 'hours: 2 days, no holiday' );
137             $diff_days = $calendar->days_between( $now, $nov_7 )->delta_days;
138             is( $diff_days, 2, 'days: 2 days, no holiday' );
139
140             # Between 5th and 12th
141             $diff_hours = $calendar->hours_between( $now, $nov_12 )->hours;
142             is( $diff_hours, 7 * 24, 'hours: 7 days, no holiday' );
143             $diff_days = $calendar->days_between( $now, $nov_12 )->delta_days;
144             is( $diff_days, 7, 'days: 7 days, no holiday' );
145
146             # Between 5th and 15th
147             $diff_hours = $calendar->hours_between( $now, $nov_15 )->hours;
148             is( $diff_hours, 10 * 24, 'hours: 10 days, no holiday' );
149             $diff_days = $calendar->days_between( $now, $nov_15 )->delta_days;
150             is( $diff_days, 10, 'days: 10 days, no holiday' );
151         };
152
153         subtest 'Different hours' => sub {
154
155             plan tests => 10;
156
157             # Between 5th and 5th (Same day short hours loan)
158             my $diff_hours = $calendar->hours_between( $now, $now->clone->add(hours => 3) )->hours;
159             is( $diff_hours, 3, 'hours: 3 hours, no holidays' );
160             my $diff_days = $calendar->days_between( $now, $now->clone->add(hours => 3) )->delta_days;
161             is( $diff_days, 0, 'days: 3 hours, no holidays' );
162
163             # Between 5th and 6th
164             $diff_hours = $calendar->hours_between( $now, $nov_6->clone->subtract(hours => 3) )->hours;
165             is( $diff_hours, 1 * 24 - 3, 'hours: 21 hours, no holidays' );
166             $diff_days = $calendar->days_between( $now, $nov_6->clone->subtract(hours => 3) )->delta_days;
167             is( $diff_days, 1, 'days: 21 hours, no holidays' );
168
169             # Between 5th and 7th
170             $diff_hours = $calendar->hours_between( $now, $nov_7->clone->subtract(hours => 3) )->hours;
171             is( $diff_hours, 2 * 24 - 3, 'hours: 45 hours, no holidays' );
172             $diff_days = $calendar->days_between( $now, $nov_7->clone->subtract(hours => 3) )->delta_days;
173             is( $diff_days, 2, 'days: 45 hours, no holidays' );
174
175             # Between 5th and 12th
176             $diff_hours = $calendar->hours_between( $now, $nov_12->clone->subtract(hours => 3) )->hours;
177             is( $diff_hours, 7 * 24 - 3, 'hours: 165 hours, no holidays' );
178             $diff_days = $calendar->days_between( $now, $nov_12->clone->subtract(hours => 3) )->delta_days;
179             is( $diff_days, 7, 'days: 165 hours, no holidays' );
180
181             # Between 5th and 15th
182             $diff_hours = $calendar->hours_between( $now, $nov_15->clone->subtract(hours => 3) )->hours;
183             is( $diff_hours, 10 * 24 - 3, 'hours: 237 hours, no holidays' );
184             $diff_days = $calendar->days_between( $now, $nov_15->clone->subtract(hours => 3) )->delta_days;
185             is( $diff_days, 10, 'days: 237 hours, no holidays' );
186         };
187     };
188
189     subtest 'With holiday' => sub {
190         plan tests => 2;
191
192         my $library = $builder->build_object({ class => 'Koha::Libraries' });
193
194         # Wednesdays are closed
195         my $dbh = C4::Context->dbh;
196         $dbh->do(q|
197             INSERT INTO repeatable_holidays (branchcode,weekday,day,month,title,description)
198             VALUES ( ?, ?, NULL, NULL, ?, '' )
199         |, undef, $library->branchcode, 3, 'Closed on Wednesday');
200
201         my $calendar = Koha::Calendar->new( branchcode => $library->branchcode );
202
203         subtest 'Same hours' => sub {
204             plan tests => 12;
205
206             my ( $diff_hours, $diff_days );
207
208             # Between 5th and 6th (This case should never happen in real code, one cannot return on a closed day)
209             $diff_hours = $calendar->hours_between( $now, $nov_6 )->hours;
210             is( $diff_hours, 0 * 24, 'hours: 1 day, end_dt = holiday' ); # FIXME Is this really should be 0?
211             $diff_days = $calendar->days_between( $now, $nov_6)->delta_days;
212             is( $diff_days, 0, 'days: 1 day, end_dt = holiday' ); # FIXME Is this really should be 0?
213
214             # Between 6th and 7th (This case should never happen in real code, one cannot issue on a closed day)
215             $diff_hours = $calendar->hours_between( $nov_6, $nov_7 )->hours;
216             is( $diff_hours, 0 * 24, 'hours: 1 day, start_dt = holiday' ); # FIXME Is this really should be 0?
217             $diff_days = $calendar->days_between( $nov_6, $nov_7 )->delta_days;
218             is( $diff_days, 0, 'days: 1 day, start_dt = holiday' ); # FIXME Is this really should be 0?
219
220             # Between 5th and 7th
221             $diff_hours = $calendar->hours_between( $now, $nov_7 )->hours;
222             is( $diff_hours, 2 * 24 - 1 * 24, 'hours: 2 days, 1 holiday' );
223             $diff_days = $calendar->days_between( $now, $nov_7 )->delta_days;
224             is( $diff_days, 2 - 1, 'days: 2 days, 1 holiday' );
225
226             # Between 5th and 12th
227             $diff_hours = $calendar->hours_between( $now, $nov_12 )->hours;
228             is( $diff_hours, 7 * 24 - 1 * 24, 'hours: 7 days, 1 holiday' );
229             $diff_days = $calendar->days_between( $now, $nov_12)->delta_days;
230             is( $diff_days, 7 - 1, 'day: 7 days, 1 holiday' );
231
232             # Between 5th and 13th
233             $diff_hours = $calendar->hours_between( $now, $nov_13 )->hours;
234             is( $diff_hours, 8 * 24 - 2 * 24, 'hours: 8 days, 2 holidays' );
235             $diff_days = $calendar->days_between( $now, $nov_13)->delta_days;
236             is( $diff_days, 8 - 2, 'days: 8 days, 2 holidays' );
237
238             # Between 5th and 15th
239             $diff_hours = $calendar->hours_between( $now, $nov_15 )->hours;
240             is( $diff_hours, 10 * 24 - 2 * 24, 'hours: 10 days, 2 holidays' );
241             $diff_days = $calendar->days_between( $now, $nov_15)->delta_days;
242             is( $diff_days, 10 - 2, 'days: 10 days, 2 holidays' );
243         };
244
245         subtest 'Different hours' => sub {
246             plan tests => 14;
247
248             my ( $diff_hours, $diff_days );
249
250             # Between 5th and 5th (Same day short hours loan)
251             # No test - Tested above as 5th is an open day
252
253             # Between 5th and 6th (This case should never happen in real code, one cannot return on a closed day)
254             my $duration = $calendar->hours_between( $now, $nov_6->clone->subtract(hours => 3) );
255             is( $duration->hours, abs(0 * 24 - 3), 'hours: 21 hours, end_dt = holiday' ); # FIXME $duration->hours always return a abs
256             is( $duration->is_negative, 1, '? is negative ?' ); # FIXME Do really test for that case in our calls to hours_between?
257             $duration = $calendar->days_between( $now, $nov_6->clone->subtract(hours => 3) );
258             is( $duration->hours, abs(0), 'days: 21 hours, end_dt = holiday' ); # FIXME Is this correct?
259
260             # Between 6th and 7th (This case should never happen in real code, one cannot issue on a closed day)
261             $duration = $calendar->hours_between( $nov_6, $nov_7->clone->subtract(hours => 3) );
262             is( $duration->hours, abs(0 * 24 - 3), 'hours: 21 hours, start_dt = holiday' ); # FIXME $duration->hours always return a abs
263             is( $duration->is_negative, 1, '? is negative ?' ); # FIXME Do really test for that case in our calls to hours_between?
264             $duration = $calendar->days_between( $nov_6, $nov_7->clone->subtract(hours => 3) );
265             is( $duration->hours, abs(0), 'days: 21 hours, start_dt = holiday' ); # FIXME Is this correct?
266
267             # Between 5th and 7th
268             $diff_hours = $calendar->hours_between( $now, $nov_7->clone->subtract(hours => 3) )->hours;
269             is( $diff_hours, 2 * 24 - 1 * 24 - 3, 'hours: 45 hours, 1 holiday' );
270             $diff_days = $calendar->days_between( $now, $nov_7->clone->subtract(hours => 3) )->delta_days;
271             is( $diff_days, 2 - 1, 'days: 45 hours, 1 holiday' );
272
273             # Between 5th and 12th
274             $diff_hours = $calendar->hours_between( $now, $nov_12->clone->subtract(hours => 3) )->hours;
275             is( $diff_hours, 7 * 24 - 1 * 24 - 3, 'hours: 165 hours, 1 holiday' );
276             $diff_days = $calendar->days_between( $now, $nov_12->clone->subtract(hours => 3) )->delta_days;
277             is( $diff_days, 7 - 1, 'days: 165 hours, 1 holiday' );
278
279             # Between 5th and 13th
280             $diff_hours = $calendar->hours_between( $now, $nov_13->clone->subtract(hours => 3) )->hours;
281             is( $diff_hours, 8 * 24 - 2 * 24 - 3, 'hours: 289 hours, 2 holidays ' );
282             $diff_days = $calendar->days_between( $now, $nov_13->clone->subtract(hours => 3) )->delta_days;
283             is( $diff_days, 8 - 1, 'days: 289 hours, 2 holidays' );
284
285             # Between 5th and 15th
286             $diff_hours = $calendar->hours_between( $now, $nov_15->clone->subtract(hours => 3) )->hours;
287             is( $diff_hours, 10 * 24 - 2 * 24 - 3, 'hours: 237 hours, 2 holidays' );
288             $diff_days = $calendar->days_between( $now, $nov_15->clone->subtract(hours => 3) )->delta_days;
289             is( $diff_days, 10 - 2, 'days: 237 hours, 2 holidays' );
290         };
291
292     };
293
294     Time::Fake->reset;
295 };
296
297 subtest 'is_holiday' => sub {
298     plan tests => 1;
299
300     subtest 'weekday holidays' => sub {
301         plan tests => 7;
302
303         my $library = $builder->build_object( { class => 'Koha::Libraries' } );
304
305         my $day = dt_from_string();
306         my $dow = scalar $day->day_of_week;
307         $dow = 0 if $dow == 7;
308
309         # Closed this day of the week
310         my $dbh = C4::Context->dbh;
311         $dbh->do(
312             q|
313             INSERT INTO repeatable_holidays (branchcode,weekday,day,month,title,description)
314             VALUES ( ?, ?, NULL, NULL, ?, '' )
315         |, undef, $library->branchcode, $dow, "TEST"
316         );
317
318         # Iterate 7 days
319         my $sth = $dbh->prepare(
320 "UPDATE repeatable_holidays SET weekday = ? WHERE branchcode = ? AND title = 'TEST'"
321         );
322         for my $i ( 0 .. 6 ) {
323             my $calendar =
324               Koha::Calendar->new( branchcode => $library->branchcode );
325
326             is( $calendar->is_holiday($day), 1, $day->day_name() ." works as a repeatable holiday");
327
328             # Increment the date and holiday day
329             $day->add( days => 1 );
330             $dow++;
331             $dow = 0 if $dow == 7;
332             $sth->execute($dow, $library->branchcode);
333         }
334     };
335 };
336
337 subtest 'get_push_amt' => sub {
338     plan tests => 1;
339
340     t::lib::Mocks::mock_preference('useDaysMode', 'Dayweek');
341
342     subtest 'weekday holidays' => sub {
343         plan tests => 7;
344
345         my $library = $builder->build_object( { class => 'Koha::Libraries' } );
346
347         my $day = dt_from_string();
348         my $dow = scalar $day->day_of_week;
349         $dow = 0 if $dow == 7;
350
351         # Closed this day of the week
352         my $dbh = C4::Context->dbh;
353         $dbh->do(
354             q|
355             INSERT INTO repeatable_holidays (branchcode,weekday,day,month,title,description)
356             VALUES ( ?, ?, NULL, NULL, ?, '' )
357         |, undef, $library->branchcode, $dow, "TEST"
358         );
359
360         # Iterate 7 days
361         my $sth = $dbh->prepare(
362 "UPDATE repeatable_holidays SET weekday = ? WHERE branchcode = ? AND title = 'TEST'"
363         );
364         for my $i ( 0 .. 6 ) {
365             my $calendar =
366               Koha::Calendar->new( branchcode => $library->branchcode, days_mode => 'Dayweek' );
367
368             my $npa;
369             eval {
370                 local $SIG{ALRM} = sub { die "alarm\n" };    # NB: \n required
371                 alarm 2;
372                 $npa = $calendar->next_open_days( $day, 0 );
373                 alarm 0;
374             };
375             if ($@) {
376                 die unless $@ eq "alarm\n";    # propagate unexpected errors
377                 # timed out
378                 ok(0, "next_push_amt succeeded for ".$day->day_name()." weekday holiday");
379             }
380             else {
381                 ok($npa, "next_push_amt succeeded for ".$day->day_name()." weekday holiday");
382             }
383
384             # Increment the date and holiday day
385             $day->add( days => 1 );
386             $dow++;
387             $dow = 0 if $dow == 7;
388             $sth->execute( $dow, $library->branchcode );
389         }
390     };
391 };
392
393 $schema->storage->txn_rollback();