2022-12-01 15:03:56 +01:00
|
|
|
<?php
|
|
|
|
|
2024-07-02 11:50:10 +02:00
|
|
|
use Roundcube\Tests\StderrMock;
|
|
|
|
|
2022-12-01 15:03:56 +01:00
|
|
|
/**
|
|
|
|
* libcalendaring_recurrence tests
|
|
|
|
*
|
|
|
|
* @author Aleksander Machniak <machniak@apheleia-it.ch>
|
|
|
|
*
|
|
|
|
* Copyright (C) 2022, Apheleia IT AG <contact@apheleia-it.ch>
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU Affero General Public License as
|
|
|
|
* published by the Free Software Foundation, either version 3 of the
|
|
|
|
* License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU Affero General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
class RecurrenceTest extends PHPUnit\Framework\TestCase
|
|
|
|
{
|
|
|
|
private $plugin;
|
|
|
|
|
2024-01-24 11:24:41 +01:00
|
|
|
public function setUp(): void
|
2022-12-01 15:03:56 +01:00
|
|
|
{
|
|
|
|
$rcube = rcmail::get_instance();
|
|
|
|
$rcube->plugins->load_plugin('libcalendaring', true, true);
|
|
|
|
|
|
|
|
$this->plugin = $rcube->plugins->get_plugin('libcalendaring');
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2022-12-02 15:57:59 +01:00
|
|
|
* Data for test_end()
|
2022-12-01 15:03:56 +01:00
|
|
|
*/
|
2024-01-24 11:24:41 +01:00
|
|
|
public function data_end()
|
2022-12-01 15:03:56 +01:00
|
|
|
{
|
2022-12-02 15:57:59 +01:00
|
|
|
return [
|
|
|
|
// non-recurring
|
|
|
|
[
|
|
|
|
[
|
|
|
|
'recurrence' => [],
|
2024-01-24 11:24:41 +01:00
|
|
|
'start' => new DateTime('2017-08-31 11:00:00'),
|
2022-12-02 15:57:59 +01:00
|
|
|
],
|
|
|
|
'2017-08-31 11:00:00', // expected result
|
|
|
|
],
|
|
|
|
// daily
|
|
|
|
[
|
|
|
|
[
|
|
|
|
'recurrence' => ['FREQ' => 'DAILY', 'INTERVAL' => '1', 'COUNT' => 2],
|
2024-01-24 11:24:41 +01:00
|
|
|
'start' => new DateTime('2017-08-31 11:00:00'),
|
2022-12-02 15:57:59 +01:00
|
|
|
],
|
|
|
|
'2017-09-01 11:00:00',
|
|
|
|
],
|
|
|
|
// weekly
|
|
|
|
[
|
|
|
|
[
|
|
|
|
'recurrence' => ['FREQ' => 'WEEKLY', 'COUNT' => 3],
|
|
|
|
'start' => new DateTime('2017-08-31 11:00:00'), // Thursday
|
|
|
|
],
|
|
|
|
'2017-09-14 11:00:00',
|
|
|
|
],
|
|
|
|
// UNTIL
|
|
|
|
[
|
|
|
|
[
|
|
|
|
'recurrence' => ['FREQ' => 'WEEKLY', 'COUNT' => 3, 'UNTIL' => new DateTime('2017-09-07 11:00:00')],
|
|
|
|
'start' => new DateTime('2017-08-31 11:00:00'), // Thursday
|
|
|
|
],
|
|
|
|
'2017-09-07 11:00:00',
|
|
|
|
],
|
|
|
|
// Infinite recurrence, no count, no until
|
|
|
|
[
|
|
|
|
[
|
|
|
|
'recurrence' => ['FREQ' => 'WEEKLY', 'INTERVAL' => '1'],
|
|
|
|
'start' => new DateTime('2017-08-31 11:00:00'), // Thursday
|
|
|
|
],
|
|
|
|
'2084-09-21 11:00:00',
|
|
|
|
],
|
2022-12-01 15:03:56 +01:00
|
|
|
|
2022-12-02 15:57:59 +01:00
|
|
|
// TODO: Test an event with EXDATE/RDATEs
|
|
|
|
];
|
2022-12-01 15:03:56 +01:00
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Data for test_first_occurrence()
|
|
|
|
*/
|
2024-01-24 11:24:41 +01:00
|
|
|
public function data_first_occurrence()
|
2022-12-01 15:03:56 +01:00
|
|
|
{
|
|
|
|
// TODO: BYYEARDAY, BYWEEKNO, BYSETPOS, WKST
|
|
|
|
|
2024-01-24 11:24:41 +01:00
|
|
|
return [
|
2022-12-01 15:03:56 +01:00
|
|
|
// non-recurring
|
2024-01-24 11:24:41 +01:00
|
|
|
[
|
|
|
|
[], // recurrence data
|
2022-12-01 15:03:56 +01:00
|
|
|
'2017-08-31 11:00:00', // start date
|
|
|
|
'2017-08-31 11:00:00', // expected result
|
2024-01-24 11:24:41 +01:00
|
|
|
],
|
2022-12-01 15:03:56 +01:00
|
|
|
// daily
|
2024-01-24 11:24:41 +01:00
|
|
|
[
|
|
|
|
['FREQ' => 'DAILY', 'INTERVAL' => '1'], // recurrence data
|
2022-12-01 15:03:56 +01:00
|
|
|
'2017-08-31 11:00:00', // start date
|
|
|
|
'2017-08-31 11:00:00', // expected result
|
2024-01-24 11:24:41 +01:00
|
|
|
],
|
2022-12-01 15:03:56 +01:00
|
|
|
// TODO: this one is not supported by the Calendar UI
|
|
|
|
/*
|
|
|
|
array(
|
|
|
|
array('FREQ' => 'DAILY', 'INTERVAL' => '1', 'BYMONTH' => 1),
|
|
|
|
'2017-08-31 11:00:00',
|
|
|
|
'2018-01-01 11:00:00',
|
|
|
|
),
|
|
|
|
*/
|
|
|
|
// weekly
|
2024-01-24 11:24:41 +01:00
|
|
|
[
|
|
|
|
['FREQ' => 'WEEKLY', 'INTERVAL' => '1'],
|
2022-12-01 15:03:56 +01:00
|
|
|
'2017-08-31 11:00:00', // Thursday
|
|
|
|
'2017-08-31 11:00:00',
|
2024-01-24 11:24:41 +01:00
|
|
|
],
|
|
|
|
[
|
|
|
|
['FREQ' => 'WEEKLY', 'INTERVAL' => '1', 'BYDAY' => 'WE'],
|
2022-12-01 15:03:56 +01:00
|
|
|
'2017-08-31 11:00:00', // Thursday
|
|
|
|
'2017-09-06 11:00:00',
|
2024-01-24 11:24:41 +01:00
|
|
|
],
|
|
|
|
[
|
|
|
|
['FREQ' => 'WEEKLY', 'INTERVAL' => '1', 'BYDAY' => 'TH'],
|
2022-12-01 15:03:56 +01:00
|
|
|
'2017-08-31 11:00:00', // Thursday
|
|
|
|
'2017-08-31 11:00:00',
|
2024-01-24 11:24:41 +01:00
|
|
|
],
|
|
|
|
[
|
|
|
|
['FREQ' => 'WEEKLY', 'INTERVAL' => '1', 'BYDAY' => 'FR'],
|
2022-12-01 15:03:56 +01:00
|
|
|
'2017-08-31 11:00:00', // Thursday
|
|
|
|
'2017-09-01 11:00:00',
|
2024-01-24 11:24:41 +01:00
|
|
|
],
|
|
|
|
[
|
|
|
|
['FREQ' => 'WEEKLY', 'INTERVAL' => '2'],
|
2022-12-01 15:03:56 +01:00
|
|
|
'2017-08-31 11:00:00', // Thursday
|
|
|
|
'2017-08-31 11:00:00',
|
2024-01-24 11:24:41 +01:00
|
|
|
],
|
|
|
|
[
|
|
|
|
['FREQ' => 'WEEKLY', 'INTERVAL' => '3', 'BYDAY' => 'WE'],
|
2022-12-01 15:03:56 +01:00
|
|
|
'2017-08-31 11:00:00', // Thursday
|
|
|
|
'2017-09-20 11:00:00',
|
2024-01-24 11:24:41 +01:00
|
|
|
],
|
|
|
|
[
|
|
|
|
['FREQ' => 'WEEKLY', 'INTERVAL' => '1', 'BYDAY' => 'WE', 'COUNT' => 1],
|
2022-12-01 15:03:56 +01:00
|
|
|
'2017-08-31 11:00:00', // Thursday
|
|
|
|
'2017-09-06 11:00:00',
|
2024-01-24 11:24:41 +01:00
|
|
|
],
|
|
|
|
[
|
|
|
|
['FREQ' => 'WEEKLY', 'INTERVAL' => '1', 'BYDAY' => 'WE', 'UNTIL' => '2017-09-01'],
|
2022-12-01 15:03:56 +01:00
|
|
|
'2017-08-31 11:00:00', // Thursday
|
|
|
|
'',
|
2024-01-24 11:24:41 +01:00
|
|
|
],
|
2022-12-01 15:03:56 +01:00
|
|
|
// monthly
|
2024-01-24 11:24:41 +01:00
|
|
|
[
|
|
|
|
['FREQ' => 'MONTHLY', 'INTERVAL' => '1'],
|
2022-12-01 15:03:56 +01:00
|
|
|
'2017-09-08 11:00:00',
|
|
|
|
'2017-09-08 11:00:00',
|
2024-01-24 11:24:41 +01:00
|
|
|
],
|
|
|
|
[
|
|
|
|
['FREQ' => 'MONTHLY', 'INTERVAL' => '1', 'BYMONTHDAY' => '8,9'],
|
2022-12-01 15:03:56 +01:00
|
|
|
'2017-08-31 11:00:00',
|
|
|
|
'2017-09-08 11:00:00',
|
2024-01-24 11:24:41 +01:00
|
|
|
],
|
|
|
|
[
|
|
|
|
['FREQ' => 'MONTHLY', 'INTERVAL' => '1', 'BYMONTHDAY' => '8,9'],
|
2022-12-01 15:03:56 +01:00
|
|
|
'2017-09-08 11:00:00',
|
|
|
|
'2017-09-08 11:00:00',
|
2024-01-24 11:24:41 +01:00
|
|
|
],
|
|
|
|
[
|
|
|
|
['FREQ' => 'MONTHLY', 'INTERVAL' => '1', 'BYDAY' => '1WE'],
|
2022-12-01 15:03:56 +01:00
|
|
|
'2017-08-16 11:00:00',
|
|
|
|
'2017-09-06 11:00:00',
|
2024-01-24 11:24:41 +01:00
|
|
|
],
|
|
|
|
[
|
|
|
|
['FREQ' => 'MONTHLY', 'INTERVAL' => '1', 'BYDAY' => '-1WE'],
|
2022-12-01 15:03:56 +01:00
|
|
|
'2017-08-16 11:00:00',
|
|
|
|
'2017-08-30 11:00:00',
|
2024-01-24 11:24:41 +01:00
|
|
|
],
|
|
|
|
[
|
|
|
|
['FREQ' => 'MONTHLY', 'INTERVAL' => '2'],
|
2022-12-01 15:03:56 +01:00
|
|
|
'2017-09-08 11:00:00',
|
|
|
|
'2017-09-08 11:00:00',
|
2024-01-24 11:24:41 +01:00
|
|
|
],
|
|
|
|
[
|
|
|
|
['FREQ' => 'MONTHLY', 'INTERVAL' => '2', 'BYMONTHDAY' => '8'],
|
2022-12-01 15:03:56 +01:00
|
|
|
'2017-08-31 11:00:00',
|
|
|
|
'2017-09-08 11:00:00', // ??????
|
2024-01-24 11:24:41 +01:00
|
|
|
],
|
2022-12-01 15:03:56 +01:00
|
|
|
// yearly
|
2024-01-24 11:24:41 +01:00
|
|
|
[
|
|
|
|
['FREQ' => 'YEARLY', 'INTERVAL' => '1'],
|
2022-12-01 15:03:56 +01:00
|
|
|
'2017-08-16 12:00:00',
|
|
|
|
'2017-08-16 12:00:00',
|
2024-01-24 11:24:41 +01:00
|
|
|
],
|
|
|
|
[
|
|
|
|
['FREQ' => 'YEARLY', 'INTERVAL' => '1', 'BYMONTH' => '8'],
|
2022-12-01 15:03:56 +01:00
|
|
|
'2017-08-16 12:00:00',
|
|
|
|
'2017-08-16 12:00:00',
|
2024-01-24 11:24:41 +01:00
|
|
|
],
|
2022-12-01 15:03:56 +01:00
|
|
|
/*
|
2022-12-20 14:15:39 +01:00
|
|
|
// Not supported by Sabre (requires BYMONTH too)
|
2022-12-01 15:03:56 +01:00
|
|
|
array(
|
|
|
|
array('FREQ' => 'YEARLY', 'INTERVAL' => '1', 'BYDAY' => '-1MO'),
|
|
|
|
'2017-08-16 11:00:00',
|
|
|
|
'2017-12-25 11:00:00',
|
|
|
|
),
|
|
|
|
*/
|
2024-01-24 11:24:41 +01:00
|
|
|
[
|
|
|
|
['FREQ' => 'YEARLY', 'INTERVAL' => '1', 'BYMONTH' => '8', 'BYDAY' => '-1MO'],
|
2022-12-01 15:03:56 +01:00
|
|
|
'2017-08-16 11:00:00',
|
|
|
|
'2017-08-28 11:00:00',
|
2024-01-24 11:24:41 +01:00
|
|
|
],
|
|
|
|
[
|
|
|
|
['FREQ' => 'YEARLY', 'INTERVAL' => '1', 'BYMONTH' => '1', 'BYDAY' => '1MO'],
|
2022-12-01 15:03:56 +01:00
|
|
|
'2017-08-16 11:00:00',
|
|
|
|
'2018-01-01 11:00:00',
|
2024-01-24 11:24:41 +01:00
|
|
|
],
|
|
|
|
[
|
|
|
|
['FREQ' => 'YEARLY', 'INTERVAL' => '1', 'BYMONTH' => '1,9', 'BYDAY' => '1MO'],
|
2022-12-01 15:03:56 +01:00
|
|
|
'2017-08-16 11:00:00',
|
|
|
|
'2017-09-04 11:00:00',
|
2024-01-24 11:24:41 +01:00
|
|
|
],
|
|
|
|
[
|
|
|
|
['FREQ' => 'YEARLY', 'INTERVAL' => '2'],
|
2022-12-01 15:03:56 +01:00
|
|
|
'2017-08-16 11:00:00',
|
|
|
|
'2017-08-16 11:00:00',
|
2024-01-24 11:24:41 +01:00
|
|
|
],
|
|
|
|
[
|
|
|
|
['FREQ' => 'YEARLY', 'INTERVAL' => '2', 'BYMONTH' => '8'],
|
2022-12-01 15:03:56 +01:00
|
|
|
'2017-08-16 11:00:00',
|
|
|
|
'2017-08-16 11:00:00',
|
2024-01-24 11:24:41 +01:00
|
|
|
],
|
2022-12-01 15:03:56 +01:00
|
|
|
/*
|
2022-12-20 14:15:39 +01:00
|
|
|
// Not supported by Sabre (requires BYMONTH too)
|
2022-12-01 15:03:56 +01:00
|
|
|
array(
|
|
|
|
array('FREQ' => 'YEARLY', 'INTERVAL' => '2', 'BYDAY' => '-1MO'),
|
|
|
|
'2017-08-16 11:00:00',
|
|
|
|
'2017-12-25 11:00:00',
|
|
|
|
),
|
|
|
|
*/
|
|
|
|
// on dates (FIXME: do we really expect the first occurrence to be on the start date?)
|
2024-01-24 11:24:41 +01:00
|
|
|
[
|
|
|
|
['RDATE' => [new DateTime('2017-08-10 11:00:00 Europe/Warsaw')]],
|
2022-12-01 15:03:56 +01:00
|
|
|
'2017-08-01 11:00:00',
|
|
|
|
'2017-08-01 11:00:00',
|
2024-01-24 11:24:41 +01:00
|
|
|
],
|
|
|
|
];
|
2022-12-01 15:03:56 +01:00
|
|
|
}
|
|
|
|
|
2022-12-02 15:57:59 +01:00
|
|
|
/**
|
|
|
|
* Test for libcalendaring_recurrence::end()
|
|
|
|
*
|
|
|
|
* @dataProvider data_end
|
|
|
|
*/
|
2024-01-24 11:24:41 +01:00
|
|
|
public function test_end($event, $expected)
|
2022-12-02 15:57:59 +01:00
|
|
|
{
|
|
|
|
$recurrence = new libcalendaring_recurrence($this->plugin, $event);
|
|
|
|
|
|
|
|
$end = $recurrence->end();
|
|
|
|
|
|
|
|
$this->assertSame($expected, $end ? $end->format('Y-m-d H:i:s') : $end);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Test for libcalendaring_recurrence::first_occurrence()
|
|
|
|
*
|
|
|
|
* @dataProvider data_first_occurrence
|
|
|
|
*/
|
2024-01-24 11:24:41 +01:00
|
|
|
public function test_first_occurrence($recurrence_data, $start, $expected)
|
2022-12-02 15:57:59 +01:00
|
|
|
{
|
|
|
|
$start = new DateTime($start);
|
|
|
|
if (!empty($recurrence_data['UNTIL'])) {
|
|
|
|
$recurrence_data['UNTIL'] = new DateTime($recurrence_data['UNTIL']);
|
|
|
|
}
|
|
|
|
|
|
|
|
$recurrence = $this->plugin->get_recurrence();
|
|
|
|
|
2024-04-18 14:03:46 +02:00
|
|
|
StderrMock::start();
|
2022-12-02 15:57:59 +01:00
|
|
|
$recurrence->init($recurrence_data, $start);
|
|
|
|
$first = $recurrence->first_occurrence();
|
2024-04-18 14:03:46 +02:00
|
|
|
StderrMock::stop();
|
2022-12-02 15:57:59 +01:00
|
|
|
|
|
|
|
$this->assertEquals($expected, $first ? $first->format('Y-m-d H:i:s') : '');
|
|
|
|
}
|
|
|
|
|
2022-12-01 15:03:56 +01:00
|
|
|
/**
|
|
|
|
* Test for libcalendaring_recurrence::first_occurrence() for all-day events
|
|
|
|
*
|
|
|
|
* @dataProvider data_first_occurrence
|
|
|
|
*/
|
2024-01-24 11:24:41 +01:00
|
|
|
public function test_first_occurrence_allday($recurrence_data, $start, $expected)
|
2022-12-01 15:03:56 +01:00
|
|
|
{
|
|
|
|
$start = new libcalendaring_datetime($start);
|
|
|
|
$start->_dateonly = true;
|
|
|
|
|
|
|
|
if (!empty($recurrence_data['UNTIL'])) {
|
|
|
|
$recurrence_data['UNTIL'] = new DateTime($recurrence_data['UNTIL']);
|
|
|
|
}
|
|
|
|
|
|
|
|
$recurrence = $this->plugin->get_recurrence();
|
|
|
|
|
2024-04-18 14:03:46 +02:00
|
|
|
StderrMock::start();
|
2022-12-01 15:03:56 +01:00
|
|
|
$recurrence->init($recurrence_data, $start);
|
|
|
|
$first = $recurrence->first_occurrence();
|
2024-04-18 14:03:46 +02:00
|
|
|
StderrMock::stop();
|
2022-12-01 15:03:56 +01:00
|
|
|
|
|
|
|
$this->assertEquals($expected, $first ? $first->format('Y-m-d H:i:s') : '');
|
|
|
|
|
|
|
|
if ($expected) {
|
|
|
|
$this->assertTrue($first->_dateonly);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-18 13:53:13 +02:00
|
|
|
/**
|
|
|
|
* Test for an event with invalid recurrence
|
|
|
|
*/
|
|
|
|
public function test_invalid_recurrence_event()
|
|
|
|
{
|
|
|
|
date_default_timezone_set('Europe/Berlin');
|
|
|
|
|
|
|
|
// This is an event with no RRULE, but one RDATE, however the RDATE is cancelled by EXDATE.
|
|
|
|
// This normally causes Sabre\VObject\Recur\NoInstancesException. We make sure it does not happen.
|
|
|
|
// The same will probably happen on any event without recurrence passed to libcalendring_vcalendar.
|
|
|
|
|
|
|
|
$vcal = <<<EOF
|
|
|
|
BEGIN:VCALENDAR
|
|
|
|
VERSION:2.0
|
|
|
|
PRODID:-//Apple Inc.//iCal 5.0.3//EN
|
|
|
|
CALSCALE:GREGORIAN
|
|
|
|
BEGIN:VEVENT
|
|
|
|
UID:fb1cb690-b963-4ea5-b58f-ac9773e36d9a
|
|
|
|
DTSTART;TZID=Europe/Berlin:20210604T093000
|
|
|
|
DTEND;TZID=Europe/Berlin:20210606T093000
|
|
|
|
RDATE:20210604T073000Z
|
|
|
|
EXDATE;TZID=Europe/Berlin:20210604T093000
|
|
|
|
DTSTAMP:20210528T091628Z
|
|
|
|
LAST-MODIFIED:20210528T091628Z
|
|
|
|
CREATED:20210528T091213Z
|
|
|
|
END:VEVENT
|
|
|
|
END:VCALENDAR
|
|
|
|
EOF;
|
|
|
|
|
|
|
|
$ical = new libcalendaring_vcalendar();
|
|
|
|
$event = $ical->import($vcal)[0];
|
|
|
|
|
|
|
|
$recurrence = new libcalendaring_recurrence($this->plugin, $event);
|
|
|
|
|
|
|
|
$this->assertSame($event['start']->format('Y-m-d H:i:s'), $recurrence->end()->format('Y-m-d H:i:s'));
|
|
|
|
$this->assertSame($event['start']->format('Y-m-d H:i:s'), $recurrence->first_occurrence()->format('Y-m-d H:i:s'));
|
|
|
|
$this->assertFalse($recurrence->next_start());
|
|
|
|
$this->assertFalse($recurrence->next_instance());
|
|
|
|
}
|
|
|
|
|
2022-12-01 15:03:56 +01:00
|
|
|
/**
|
2022-12-02 14:51:33 +01:00
|
|
|
* Test for libcalendaring_recurrence::next_instance()
|
2022-12-01 15:03:56 +01:00
|
|
|
*/
|
2024-01-24 11:24:41 +01:00
|
|
|
public function test_next_instance()
|
2022-12-01 15:03:56 +01:00
|
|
|
{
|
|
|
|
date_default_timezone_set('America/New_York');
|
|
|
|
|
|
|
|
$start = new libcalendaring_datetime('2017-08-31 11:00:00', new DateTimeZone('Europe/Berlin'));
|
2022-12-02 14:51:33 +01:00
|
|
|
$event = [
|
|
|
|
'start' => $start,
|
|
|
|
'recurrence' => ['FREQ' => 'WEEKLY', 'INTERVAL' => '1'],
|
|
|
|
'allday' => true,
|
|
|
|
];
|
2022-12-01 15:03:56 +01:00
|
|
|
|
2022-12-02 14:51:33 +01:00
|
|
|
$recurrence = new libcalendaring_recurrence($this->plugin, $event);
|
|
|
|
$next = $recurrence->next_instance();
|
2022-12-01 15:03:56 +01:00
|
|
|
|
2022-12-02 14:51:33 +01:00
|
|
|
$this->assertEquals($start->format('2017-09-07 H:i:s'), $next['start']->format('Y-m-d H:i:s'), 'Same time');
|
|
|
|
$this->assertEquals($start->getTimezone()->getName(), $next['start']->getTimezone()->getName(), 'Same timezone');
|
|
|
|
$this->assertTrue($next['start']->_dateonly, '_dateonly flag');
|
2022-12-01 15:03:56 +01:00
|
|
|
}
|
2022-12-20 14:15:39 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Test for libcalendaring_recurrence::next_instance()
|
|
|
|
*/
|
2024-01-24 11:24:41 +01:00
|
|
|
public function test_next_instance_exdate()
|
2022-12-20 14:15:39 +01:00
|
|
|
{
|
|
|
|
date_default_timezone_set('America/New_York');
|
|
|
|
|
|
|
|
$start = new libcalendaring_datetime('2023-01-18 10:00:00', new DateTimeZone('Europe/Berlin'));
|
|
|
|
$end = new libcalendaring_datetime('2023-01-18 10:30:00', new DateTimeZone('Europe/Berlin'));
|
|
|
|
$event = [
|
|
|
|
'start' => $start,
|
|
|
|
'end' => $end,
|
|
|
|
'recurrence' => [
|
|
|
|
'FREQ' => 'DAILY',
|
|
|
|
'INTERVAL' => '1',
|
|
|
|
'EXDATE' => [
|
|
|
|
// Exclude the start date
|
|
|
|
new libcalendaring_datetime('2023-01-18 10:00:00', new DateTimeZone('Europe/Berlin')),
|
|
|
|
],
|
|
|
|
],
|
|
|
|
];
|
|
|
|
|
|
|
|
$recurrence = new libcalendaring_recurrence($this->plugin, $event);
|
|
|
|
|
|
|
|
$next = $recurrence->next_instance();
|
|
|
|
|
|
|
|
$this->assertEquals('2023-01-19 10:00:00', $next['start']->format('Y-m-d H:i:s'));
|
|
|
|
$this->assertEquals('Europe/Berlin', $next['start']->getTimezone()->getName());
|
|
|
|
$this->assertFalse($next['start']->_dateonly);
|
|
|
|
|
|
|
|
$next = $recurrence->next_instance();
|
|
|
|
|
|
|
|
$this->assertEquals('2023-01-20 10:00:00', $next['start']->format('Y-m-d H:i:s'));
|
|
|
|
$this->assertEquals('Europe/Berlin', $next['start']->getTimezone()->getName());
|
|
|
|
$this->assertFalse($next['start']->_dateonly);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Test for libcalendaring_recurrence::next_instance()
|
|
|
|
*/
|
2024-01-24 11:24:41 +01:00
|
|
|
public function test_next_instance_dst()
|
2022-12-20 14:15:39 +01:00
|
|
|
{
|
|
|
|
date_default_timezone_set('America/New_York');
|
|
|
|
|
|
|
|
$start = new libcalendaring_datetime('2021-03-10 10:00:00', new DateTimeZone('Europe/Berlin'));
|
|
|
|
$end = new libcalendaring_datetime('2021-03-10 10:30:00', new DateTimeZone('Europe/Berlin'));
|
|
|
|
$event = [
|
|
|
|
'start' => $start,
|
|
|
|
'end' => $end,
|
|
|
|
'recurrence' => [
|
|
|
|
'FREQ' => 'MONTHLY',
|
|
|
|
'INTERVAL' => '1',
|
|
|
|
],
|
|
|
|
];
|
|
|
|
|
|
|
|
$recurrence = new libcalendaring_recurrence($this->plugin, $event);
|
|
|
|
|
|
|
|
$next = $recurrence->next_instance();
|
|
|
|
|
|
|
|
$this->assertEquals('2021-04-10 10:00:00', $next['start']->format('Y-m-d H:i:s'));
|
|
|
|
$this->assertEquals('Europe/Berlin', $next['start']->getTimezone()->getName());
|
|
|
|
|
|
|
|
$next = $recurrence->next_instance();
|
|
|
|
|
|
|
|
$this->assertEquals('2021-05-10 10:00:00', $next['start']->format('Y-m-d H:i:s'));
|
|
|
|
$this->assertEquals('Europe/Berlin', $next['start']->getTimezone()->getName());
|
|
|
|
|
|
|
|
$start = new libcalendaring_datetime('2021-10-10 10:00:00', new DateTimeZone('Europe/Berlin'));
|
|
|
|
$end = new libcalendaring_datetime('2021-10-10 10:30:00', new DateTimeZone('Europe/Berlin'));
|
|
|
|
$event = [
|
|
|
|
'start' => $start,
|
|
|
|
'end' => $end,
|
|
|
|
'recurrence' => [
|
|
|
|
'FREQ' => 'MONTHLY',
|
|
|
|
'INTERVAL' => '1',
|
|
|
|
],
|
|
|
|
];
|
|
|
|
|
|
|
|
$recurrence = new libcalendaring_recurrence($this->plugin, $event);
|
|
|
|
|
|
|
|
$next = $recurrence->next_instance();
|
|
|
|
|
|
|
|
$this->assertEquals('2021-11-10 10:00:00', $next['start']->format('Y-m-d H:i:s'));
|
|
|
|
$this->assertEquals('Europe/Berlin', $next['start']->getTimezone()->getName());
|
|
|
|
|
|
|
|
$next = $recurrence->next_instance();
|
|
|
|
|
|
|
|
$this->assertEquals('2021-12-10 10:00:00', $next['start']->format('Y-m-d H:i:s'));
|
|
|
|
$this->assertEquals('Europe/Berlin', $next['start']->getTimezone()->getName());
|
|
|
|
|
|
|
|
$next = $recurrence->next_instance();
|
|
|
|
$next = $recurrence->next_instance();
|
|
|
|
$next = $recurrence->next_instance();
|
|
|
|
$next = $recurrence->next_instance();
|
|
|
|
|
|
|
|
$this->assertEquals('2022-04-10 10:00:00', $next['start']->format('Y-m-d H:i:s'));
|
|
|
|
$this->assertEquals('Europe/Berlin', $next['start']->getTimezone()->getName());
|
|
|
|
|
|
|
|
}
|
2022-12-01 15:03:56 +01:00
|
|
|
}
|