From a9531c9336ac705188cc5e91876e48e71f995051 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Fri, 2 Dec 2022 15:57:59 +0100 Subject: [PATCH] Fix libcalendaring_recurrence::end() --- .../lib/libcalendaring_recurrence.php | 24 ++-- .../libcalendaring/tests/RecurrenceTest.php | 94 ++++++++++++--- .../libkolab/lib/kolab_date_recurrence.php | 15 +-- plugins/libkolab/libkolab.php | 1 + .../tests/KolabDateRecurrenceTest.php | 112 ++++++++++++++---- 5 files changed, 192 insertions(+), 54 deletions(-) diff --git a/plugins/libcalendaring/lib/libcalendaring_recurrence.php b/plugins/libcalendaring/lib/libcalendaring_recurrence.php index 4aca2861..4de96812 100644 --- a/plugins/libcalendaring/lib/libcalendaring_recurrence.php +++ b/plugins/libcalendaring/lib/libcalendaring_recurrence.php @@ -143,24 +143,24 @@ class libcalendaring_recurrence return $this->recurrence['UNTIL']; } - if (!$this->engine->isInfinite()) { - // run through all items till we reach the end - try { - foreach ($this->engine as $end) { - // do nothing - } - } - catch (Exception $e) { + // Run through all items till we reach the end, or limit of iterations + // Note: Sabre has a limits of iteration in VObject\Settings, so it is not an infinite loop + try { + foreach ($this->engine as $end) { // do nothing } } - else if (isset($this->event['end']) && $this->event['end'] instanceof DateTimeInterface) { + catch (Exception $e) { + // do nothing + } +/* + if (empty($end) && isset($this->event['start']) && $this->event['start'] instanceof DateTimeInterface) { // determine a reasonable end date if none given - $end = clone $this->event['end']; + $end = clone $this->event['start']; $end->add(new DateInterval('P100Y')); } - - return isset($end) ? $this->toDateTime($end, false) : false; +*/ + return isset($end) ? $this->toDateTime($end) : false; } /** diff --git a/plugins/libcalendaring/tests/RecurrenceTest.php b/plugins/libcalendaring/tests/RecurrenceTest.php index cdbb2a8d..d17257a8 100644 --- a/plugins/libcalendaring/tests/RecurrenceTest.php +++ b/plugins/libcalendaring/tests/RecurrenceTest.php @@ -34,25 +34,55 @@ class RecurrenceTest extends PHPUnit\Framework\TestCase } /** - * Test for libcalendaring_recurrence::first_occurrence() - * - * @dataProvider data_first_occurrence + * Data for test_end() */ - function test_first_occurrence($recurrence_data, $start, $expected) + function data_end() { - $start = new DateTime($start); - if (!empty($recurrence_data['UNTIL'])) { - $recurrence_data['UNTIL'] = new DateTime($recurrence_data['UNTIL']); - } + return [ + // non-recurring + [ + [ + 'recurrence' => [], + 'start' => new DateTime('2017-08-31 11:00:00') + ], + '2017-08-31 11:00:00', // expected result + ], + // daily + [ + [ + 'recurrence' => ['FREQ' => 'DAILY', 'INTERVAL' => '1', 'COUNT' => 2], + 'start' => new DateTime('2017-08-31 11:00: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', + ], - $recurrence = $this->plugin->get_recurrence(); - - $recurrence->init($recurrence_data, $start); - $first = $recurrence->first_occurrence(); - - $this->assertEquals($expected, $first ? $first->format('Y-m-d H:i:s') : ''); + // TODO: Test an event with EXDATE/RDATEs + ]; } - /** * Data for test_first_occurrence() */ @@ -223,6 +253,40 @@ class RecurrenceTest extends PHPUnit\Framework\TestCase ); } + /** + * Test for libcalendaring_recurrence::end() + * + * @dataProvider data_end + */ + function test_end($event, $expected) + { + $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 + */ + function test_first_occurrence($recurrence_data, $start, $expected) + { + $start = new DateTime($start); + if (!empty($recurrence_data['UNTIL'])) { + $recurrence_data['UNTIL'] = new DateTime($recurrence_data['UNTIL']); + } + + $recurrence = $this->plugin->get_recurrence(); + + $recurrence->init($recurrence_data, $start); + $first = $recurrence->first_occurrence(); + + $this->assertEquals($expected, $first ? $first->format('Y-m-d H:i:s') : ''); + } + /** * Test for libcalendaring_recurrence::first_occurrence() for all-day events * diff --git a/plugins/libkolab/lib/kolab_date_recurrence.php b/plugins/libkolab/lib/kolab_date_recurrence.php index f2110b03..2aaf5888 100644 --- a/plugins/libkolab/lib/kolab_date_recurrence.php +++ b/plugins/libkolab/lib/kolab_date_recurrence.php @@ -128,7 +128,7 @@ class kolab_date_recurrence $event = $this->object->to_array(); // recurrence end date is given - if ($event['recurrence']['UNTIL'] instanceof DateTimeInterface) { + if (isset($event['recurrence']['UNTIL']) && $event['recurrence']['UNTIL'] instanceof DateTimeInterface) { return $event['recurrence']['UNTIL']; } @@ -139,12 +139,13 @@ class kolab_date_recurrence return $end_dt; } - // determine a reasonable end date if none given - if (!$event['recurrence']['COUNT'] && $event['end'] instanceof DateTimeInterface) { - $end_dt = clone $event['end']; - $end_dt->add(new DateInterval('P100Y')); - - return $end_dt; + // determine a reasonable end date for an infinite recurrence + if (empty($event['recurrence']['COUNT'])) { + if (!empty($event['start']) && $event['start'] instanceof DateTimeInterface) { + $start_dt = clone $event['start']; + $start_dt->add(new DateInterval('P100Y')); + return $start_dt; + } } return false; diff --git a/plugins/libkolab/libkolab.php b/plugins/libkolab/libkolab.php index 6c5e7a7a..5b0ecbbe 100644 --- a/plugins/libkolab/libkolab.php +++ b/plugins/libkolab/libkolab.php @@ -37,6 +37,7 @@ class libkolab extends rcube_plugin { // load local config $this->load_config(); + $this->require_plugin('libcalendaring'); // extend include path to load bundled lib classes $include_path = $this->home . '/lib' . PATH_SEPARATOR . ini_get('include_path'); diff --git a/plugins/libkolab/tests/KolabDateRecurrenceTest.php b/plugins/libkolab/tests/KolabDateRecurrenceTest.php index 3c51aa19..c2ba0208 100644 --- a/plugins/libkolab/tests/KolabDateRecurrenceTest.php +++ b/plugins/libkolab/tests/KolabDateRecurrenceTest.php @@ -27,32 +27,58 @@ class KolabDateRecurrenceTest extends PHPUnit\Framework\TestCase { $rcube = rcmail::get_instance(); $rcube->plugins->load_plugin('libkolab', true, true); + $rcube->plugins->load_plugin('libcalendaring', true, true); } /** - * kolab_date_recurrence::first_occurrence() - * - * @dataProvider data_first_occurrence + * Data for test_end() */ - function test_first_occurrence($recurrence_data, $start, $expected) + function data_end() { - if (!kolab_format::supports(3)) { - $this->markTestSkipped('No Kolab support'); - } + return [ + // non-recurring + [ + [ + 'recurrence' => [], + 'start' => new DateTime('2017-08-31 11:00:00') + ], + '2117-08-31 11:00:00', // expected result + ], + // daily + [ + [ + 'recurrence' => ['FREQ' => 'DAILY', 'INTERVAL' => '1', 'COUNT' => 2], + 'start' => new DateTime('2017-08-31 11:00:00') + ], + '2017-09-01 11:00:00', + ], + // weekly + [ + [ + 'recurrence' => ['FREQ' => 'WEEKLY', 'INTERVAL' => '1', 'COUNT' => 3], + 'start' => new DateTime('2017-08-31 11:00:00'), // Thursday + ], + '2017-09-14 11:00:00', + ], + // UNTIL + [ + [ + 'recurrence' => ['FREQ' => 'WEEKLY', 'INTERVAL' => '1', '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 + ], + '2117-08-31 11:00:00', + ], - $start = new DateTime($start); - if (!empty($recurrence_data['UNTIL'])) { - $recurrence_data['UNTIL'] = new DateTime($recurrence_data['UNTIL']); - } - - $event = array('start' => $start, 'recurrence' => $recurrence_data); - $object = kolab_format::factory('event', 3.0); - $object->set($event); - - $recurrence = new kolab_date_recurrence($object); - $first = $recurrence->first_occurrence(); - - $this->assertEquals($expected, $first ? $first->format('Y-m-d H:i:s') : ''); + // TODO: Test an event with EXDATE/RDATE + ]; } /** @@ -213,6 +239,52 @@ class KolabDateRecurrenceTest extends PHPUnit\Framework\TestCase ); } + /** + * kolab_date_recurrence::end() + * + * @dataProvider data_end + */ + function test_end($event, $expected) + { + if (!kolab_format::supports(3)) { + $this->markTestSkipped('No Kolab support'); + } + + $object = kolab_format::factory('event', 3.0); + $object->set($event); + + $recurrence = new kolab_date_recurrence($object); + $end = $recurrence->end(); + + $this->assertSame($expected, $end ? $end->format('Y-m-d H:i:s') : $end); + } + + /** + * kolab_date_recurrence::first_occurrence() + * + * @dataProvider data_first_occurrence + */ + function test_first_occurrence($recurrence_data, $start, $expected) + { + if (!kolab_format::supports(3)) { + $this->markTestSkipped('No Kolab support'); + } + + $start = new DateTime($start); + if (!empty($recurrence_data['UNTIL'])) { + $recurrence_data['UNTIL'] = new DateTime($recurrence_data['UNTIL']); + } + + $event = array('start' => $start, 'recurrence' => $recurrence_data); + $object = kolab_format::factory('event', 3.0); + $object->set($event); + + $recurrence = new kolab_date_recurrence($object); + $first = $recurrence->first_occurrence(); + + $this->assertEquals($expected, $first ? $first->format('Y-m-d H:i:s') : ''); + } + /** * kolab_date_recurrence::first_occurrence() for all-day events *