1<?php
2
3namespace Sabre\VObject\Recur\EventIterator;
4
5use DateTimeImmutable;
6use DateTimeZone;
7use Sabre\VObject\Component\VCalendar;
8use Sabre\VObject\Recur;
9
10class InfiniteLoopProblemTest extends \PHPUnit_Framework_TestCase {
11
12    function setUp() {
13
14        $this->vcal = new VCalendar();
15
16    }
17
18    /**
19     * This bug came from a Fruux customer. This would result in a never-ending
20     * request.
21     */
22    function testFastForwardTooFar() {
23
24        $ev = $this->vcal->createComponent('VEVENT');
25        $ev->UID = 'foobar';
26        $ev->DTSTART = '20090420T180000Z';
27        $ev->RRULE = 'FREQ=WEEKLY;BYDAY=MO;UNTIL=20090704T205959Z;INTERVAL=1';
28
29        $this->assertFalse($ev->isInTimeRange(new DateTimeImmutable('2012-01-01 12:00:00'), new DateTimeImmutable('3000-01-01 00:00:00')));
30
31    }
32
33    /**
34     * Different bug, also likely an infinite loop.
35     */
36    function testYearlyByMonthLoop() {
37
38        $ev = $this->vcal->createComponent('VEVENT');
39        $ev->UID = 'uuid';
40        $ev->DTSTART = '20120101T154500';
41        $ev->DTSTART['TZID'] = 'Europe/Berlin';
42        $ev->RRULE = 'FREQ=YEARLY;INTERVAL=1;UNTIL=20120203T225959Z;BYMONTH=2;BYSETPOS=1;BYDAY=SU,MO,TU,WE,TH,FR,SA';
43        $ev->DTEND = '20120101T164500';
44        $ev->DTEND['TZID'] = 'Europe/Berlin';
45
46        // This recurrence rule by itself is a yearly rule that should happen
47        // every february.
48        //
49        // The BYDAY part expands this to every day of the month, but the
50        // BYSETPOS limits this to only the 1st day of the month. Very crazy
51        // way to specify this, and could have certainly been a lot easier.
52        $this->vcal->add($ev);
53
54        $it = new Recur\EventIterator($this->vcal, 'uuid');
55        $it->fastForward(new DateTimeImmutable('2012-01-29 23:00:00', new DateTimeZone('UTC')));
56
57        $collect = [];
58
59        while ($it->valid()) {
60            $collect[] = $it->getDtStart();
61            if ($it->getDtStart() > new DateTimeImmutable('2013-02-05 22:59:59', new DateTimeZone('UTC'))) {
62                break;
63            }
64            $it->next();
65
66        }
67
68        $this->assertEquals(
69            [new DateTimeImmutable('2012-02-01 15:45:00', new DateTimeZone('Europe/Berlin'))],
70            $collect
71        );
72
73    }
74
75    /**
76     * Something, somewhere produced an ics with an interval set to 0. Because
77     * this means we increase the current day (or week, month) by 0, this also
78     * results in an infinite loop.
79     *
80     * @expectedException \Sabre\VObject\InvalidDataException
81     * @return void
82     */
83    function testZeroInterval() {
84
85        $ev = $this->vcal->createComponent('VEVENT');
86        $ev->UID = 'uuid';
87        $ev->DTSTART = '20120824T145700Z';
88        $ev->RRULE = 'FREQ=YEARLY;INTERVAL=0';
89        $this->vcal->add($ev);
90
91        $it = new Recur\EventIterator($this->vcal, 'uuid');
92        $it->fastForward(new DateTimeImmutable('2013-01-01 23:00:00', new DateTimeZone('UTC')));
93
94        // if we got this far.. it means we are no longer infinitely looping
95
96    }
97
98}
99