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