1<?php
2
3namespace Sabre\VObject\Property\ICalendar;
4
5use Sabre\VObject\Component\VCalendar;
6use Sabre\VObject\Node;
7use Sabre\VObject\Reader;
8
9class RecurTest extends \PHPUnit_Framework_TestCase {
10
11    use \Sabre\VObject\PHPUnitAssertions;
12
13    function testParts() {
14
15        $vcal = new VCalendar();
16        $recur = $vcal->add('RRULE', 'FREQ=Daily');
17
18        $this->assertInstanceOf('Sabre\VObject\Property\ICalendar\Recur', $recur);
19
20        $this->assertEquals(['FREQ' => 'DAILY'], $recur->getParts());
21        $recur->setParts(['freq' => 'MONTHLY']);
22
23        $this->assertEquals(['FREQ' => 'MONTHLY'], $recur->getParts());
24
25    }
26
27    /**
28     * @expectedException \InvalidArgumentException
29     */
30    function testSetValueBadVal() {
31
32        $vcal = new VCalendar();
33        $recur = $vcal->add('RRULE', 'FREQ=Daily');
34        $recur->setValue(new \Exception());
35
36    }
37
38    function testSetValueWithCount() {
39        $vcal = new VCalendar();
40        $recur = $vcal->add('RRULE', 'FREQ=Daily');
41        $recur->setValue(['COUNT' => 3]);
42        $this->assertEquals($recur->getParts()['COUNT'], 3);
43    }
44
45    function testGetJSONWithCount() {
46        $input = 'BEGIN:VCALENDAR
47BEGIN:VEVENT
48UID:908d53c0-e1a3-4883-b69f-530954d6bd62
49TRANSP:OPAQUE
50DTSTART;TZID=Europe/Berlin:20160301T150000
51DTEND;TZID=Europe/Berlin:20160301T170000
52SUMMARY:test
53RRULE:FREQ=DAILY;COUNT=3
54ORGANIZER;CN=robert pipo:mailto:robert@example.org
55END:VEVENT
56END:VCALENDAR
57';
58
59        $vcal = Reader::read($input);
60        $rrule = $vcal->VEVENT->RRULE;
61        $count = $rrule->getJsonValue()[0]['count'];
62        $this->assertTrue(is_int($count));
63        $this->assertEquals(3, $count);
64    }
65
66    function testSetSubParts() {
67
68        $vcal = new VCalendar();
69        $recur = $vcal->add('RRULE', ['FREQ' => 'DAILY', 'BYDAY' => 'mo,tu', 'BYMONTH' => [0, 1]]);
70
71        $this->assertEquals([
72            'FREQ'    => 'DAILY',
73            'BYDAY'   => ['MO', 'TU'],
74            'BYMONTH' => [0, 1],
75        ], $recur->getParts());
76
77    }
78
79    function testGetJSONWithUntil() {
80        $input = 'BEGIN:VCALENDAR
81BEGIN:VEVENT
82UID:908d53c0-e1a3-4883-b69f-530954d6bd62
83TRANSP:OPAQUE
84DTSTART;TZID=Europe/Berlin:20160301T150000
85DTEND;TZID=Europe/Berlin:20160301T170000
86SUMMARY:test
87RRULE:FREQ=DAILY;UNTIL=20160305T230000Z
88ORGANIZER;CN=robert pipo:mailto:robert@example.org
89END:VEVENT
90END:VCALENDAR
91';
92
93        $vcal = Reader::read($input);
94        $rrule = $vcal->VEVENT->RRULE;
95        $untilJsonString = $rrule->getJsonValue()[0]['until'];
96        $this->assertEquals('2016-03-05T23:00:00Z', $untilJsonString);
97    }
98
99
100    function testValidateStripEmpties() {
101
102        $input = 'BEGIN:VCALENDAR
103VERSION:2.0
104PRODID:foobar
105BEGIN:VEVENT
106UID:908d53c0-e1a3-4883-b69f-530954d6bd62
107TRANSP:OPAQUE
108DTSTART;TZID=Europe/Berlin:20160301T150000
109DTEND;TZID=Europe/Berlin:20160301T170000
110SUMMARY:test
111RRULE:FREQ=DAILY;BYMONTH=;UNTIL=20160305T230000Z
112ORGANIZER;CN=robert pipo:mailto:robert@example.org
113DTSTAMP:20160312T183800Z
114END:VEVENT
115END:VCALENDAR
116';
117
118        $vcal = Reader::read($input);
119        $this->assertEquals(
120            1,
121            count($vcal->validate())
122        );
123        $this->assertEquals(
124            1,
125            count($vcal->validate($vcal::REPAIR))
126        );
127
128        $expected = 'BEGIN:VCALENDAR
129VERSION:2.0
130PRODID:foobar
131BEGIN:VEVENT
132UID:908d53c0-e1a3-4883-b69f-530954d6bd62
133TRANSP:OPAQUE
134DTSTART;TZID=Europe/Berlin:20160301T150000
135DTEND;TZID=Europe/Berlin:20160301T170000
136SUMMARY:test
137RRULE:FREQ=DAILY;UNTIL=20160305T230000Z
138ORGANIZER;CN=robert pipo:mailto:robert@example.org
139DTSTAMP:20160312T183800Z
140END:VEVENT
141END:VCALENDAR
142';
143
144        $this->assertVObjectEqualsVObject(
145            $expected,
146            $vcal
147        );
148
149    }
150
151    function testValidateStripNoFreq() {
152
153        $input = 'BEGIN:VCALENDAR
154VERSION:2.0
155PRODID:foobar
156BEGIN:VEVENT
157UID:908d53c0-e1a3-4883-b69f-530954d6bd62
158TRANSP:OPAQUE
159DTSTART;TZID=Europe/Berlin:20160301T150000
160DTEND;TZID=Europe/Berlin:20160301T170000
161SUMMARY:test
162RRULE:UNTIL=20160305T230000Z
163ORGANIZER;CN=robert pipo:mailto:robert@example.org
164DTSTAMP:20160312T183800Z
165END:VEVENT
166END:VCALENDAR
167';
168
169        $vcal = Reader::read($input);
170        $this->assertEquals(
171            1,
172            count($vcal->validate())
173        );
174        $this->assertEquals(
175            1,
176            count($vcal->validate($vcal::REPAIR))
177        );
178
179        $expected = 'BEGIN:VCALENDAR
180VERSION:2.0
181PRODID:foobar
182BEGIN:VEVENT
183UID:908d53c0-e1a3-4883-b69f-530954d6bd62
184TRANSP:OPAQUE
185DTSTART;TZID=Europe/Berlin:20160301T150000
186DTEND;TZID=Europe/Berlin:20160301T170000
187SUMMARY:test
188ORGANIZER;CN=robert pipo:mailto:robert@example.org
189DTSTAMP:20160312T183800Z
190END:VEVENT
191END:VCALENDAR
192';
193
194        $this->assertVObjectEqualsVObject(
195            $expected,
196            $vcal
197        );
198
199    }
200
201    function testValidateInvalidByMonthRruleWithRepair() {
202
203        $calendar = new VCalendar();
204        $property = $calendar->createProperty('RRULE', 'FREQ=YEARLY;COUNT=6;BYMONTHDAY=24;BYMONTH=0');
205        $result = $property->validate(Node::REPAIR);
206
207        $this->assertCount(1, $result);
208        $this->assertEquals('BYMONTH in RRULE must have value(s) between 1 and 12!', $result[0]['message']);
209        $this->assertEquals(1, $result[0]['level']);
210        $this->assertEquals('FREQ=YEARLY;COUNT=6;BYMONTHDAY=24', $property->getValue());
211
212    }
213
214    function testValidateInvalidByMonthRruleWithoutRepair() {
215
216        $calendar = new VCalendar();
217        $property = $calendar->createProperty('RRULE', 'FREQ=YEARLY;COUNT=6;BYMONTHDAY=24;BYMONTH=0');
218        $result = $property->validate();
219
220        $this->assertCount(1, $result);
221        $this->assertEquals('BYMONTH in RRULE must have value(s) between 1 and 12!', $result[0]['message']);
222        $this->assertEquals(3, $result[0]['level']);
223        $this->assertEquals('FREQ=YEARLY;COUNT=6;BYMONTHDAY=24;BYMONTH=0', $property->getValue());
224
225    }
226
227    function testValidateInvalidByMonthRruleWithRepair2() {
228
229        $calendar = new VCalendar();
230        $property = $calendar->createProperty('RRULE', 'FREQ=YEARLY;COUNT=6;BYMONTHDAY=24;BYMONTH=bla');
231        $result = $property->validate(Node::REPAIR);
232
233        $this->assertCount(1, $result);
234        $this->assertEquals('BYMONTH in RRULE must have value(s) between 1 and 12!', $result[0]['message']);
235        $this->assertEquals(1, $result[0]['level']);
236        $this->assertEquals('FREQ=YEARLY;COUNT=6;BYMONTHDAY=24', $property->getValue());
237
238    }
239
240    function testValidateInvalidByMonthRruleWithoutRepair2() {
241
242        $calendar = new VCalendar();
243        $property = $calendar->createProperty('RRULE', 'FREQ=YEARLY;COUNT=6;BYMONTHDAY=24;BYMONTH=bla');
244        $result = $property->validate();
245
246        $this->assertCount(1, $result);
247        $this->assertEquals('BYMONTH in RRULE must have value(s) between 1 and 12!', $result[0]['message']);
248        $this->assertEquals(3, $result[0]['level']);
249        // Without repair the invalid BYMONTH is still there, but the value is changed to uppercase
250        $this->assertEquals('FREQ=YEARLY;COUNT=6;BYMONTHDAY=24;BYMONTH=BLA', $property->getValue());
251
252    }
253
254    function testValidateInvalidByMonthRruleValue14WithRepair() {
255
256        $calendar = new VCalendar();
257        $property = $calendar->createProperty('RRULE', 'FREQ=YEARLY;COUNT=6;BYMONTHDAY=24;BYMONTH=14');
258        $result = $property->validate(Node::REPAIR);
259
260        $this->assertCount(1, $result);
261        $this->assertEquals('BYMONTH in RRULE must have value(s) between 1 and 12!', $result[0]['message']);
262        $this->assertEquals(1, $result[0]['level']);
263        $this->assertEquals('FREQ=YEARLY;COUNT=6;BYMONTHDAY=24', $property->getValue());
264
265    }
266
267    function testValidateInvalidByMonthRruleMultipleWithRepair() {
268
269        $calendar = new VCalendar();
270        $property = $calendar->createProperty('RRULE', 'FREQ=YEARLY;COUNT=6;BYMONTHDAY=24;BYMONTH=0,1,2,3,4,14');
271        $result = $property->validate(Node::REPAIR);
272
273        $this->assertCount(2, $result);
274        $this->assertEquals('BYMONTH in RRULE must have value(s) between 1 and 12!', $result[0]['message']);
275        $this->assertEquals(1, $result[0]['level']);
276        $this->assertEquals('BYMONTH in RRULE must have value(s) between 1 and 12!', $result[1]['message']);
277        $this->assertEquals(1, $result[1]['level']);
278        $this->assertEquals('FREQ=YEARLY;COUNT=6;BYMONTHDAY=24;BYMONTH=1,2,3,4', $property->getValue());
279
280    }
281
282    function testValidateOneOfManyInvalidByMonthRruleWithRepair() {
283
284        $calendar = new VCalendar();
285        $property = $calendar->createProperty('RRULE', 'FREQ=YEARLY;COUNT=6;BYMONTHDAY=24;BYMONTH=bla,3,foo');
286        $result = $property->validate(Node::REPAIR);
287
288        $this->assertCount(2, $result);
289        $this->assertEquals('BYMONTH in RRULE must have value(s) between 1 and 12!', $result[0]['message']);
290        $this->assertEquals(1, $result[0]['level']);
291        $this->assertEquals('BYMONTH in RRULE must have value(s) between 1 and 12!', $result[1]['message']);
292        $this->assertEquals(1, $result[1]['level']);
293        $this->assertEquals('FREQ=YEARLY;COUNT=6;BYMONTHDAY=24;BYMONTH=3', $property->getValue());
294
295    }
296
297    function testValidateValidByMonthRrule() {
298
299        $calendar = new VCalendar();
300        $property = $calendar->createProperty('RRULE', 'FREQ=YEARLY;COUNT=6;BYMONTHDAY=24;BYMONTH=2,3');
301        $this->assertEquals('FREQ=YEARLY;COUNT=6;BYMONTHDAY=24;BYMONTH=2,3', $property->getValue());
302
303    }
304
305    /**
306     * test for issue #336
307     */
308    function testValidateRruleBySecondZero() {
309
310        $calendar = new VCalendar();
311        $property = $calendar->createProperty('RRULE', 'FREQ=DAILY;BYHOUR=10;BYMINUTE=30;BYSECOND=0;UNTIL=20150616T153000Z');
312        $result = $property->validate(Node::REPAIR);
313
314        // There should be 0 warnings and the value should be unchanged
315        $this->assertEmpty($result);
316        $this->assertEquals('FREQ=DAILY;BYHOUR=10;BYMINUTE=30;BYSECOND=0;UNTIL=20150616T153000Z', $property->getValue());
317
318    }
319
320    function testValidateValidByWeekNoWithRepair() {
321
322        $calendar = new VCalendar();
323        $property = $calendar->createProperty('RRULE', 'FREQ=YEARLY;COUNT=6;BYWEEKNO=11');
324        $result = $property->validate(Node::REPAIR);
325
326        $this->assertCount(0, $result);
327        $this->assertEquals('FREQ=YEARLY;COUNT=6;BYWEEKNO=11', $property->getValue());
328
329    }
330
331    function testValidateInvalidByWeekNoWithRepair() {
332
333        $calendar = new VCalendar();
334        $property = $calendar->createProperty('RRULE', 'FREQ=YEARLY;COUNT=6;BYWEEKNO=55;BYDAY=WE');
335        $result = $property->validate(Node::REPAIR);
336
337        $this->assertCount(1, $result);
338        $this->assertEquals('BYWEEKNO in RRULE must have value(s) from -53 to -1, or 1 to 53!', $result[0]['message']);
339        $this->assertEquals(1, $result[0]['level']);
340        $this->assertEquals('FREQ=YEARLY;COUNT=6;BYDAY=WE', $property->getValue());
341
342    }
343
344    function testValidateMultipleInvalidByWeekNoWithRepair() {
345
346        $calendar = new VCalendar();
347        $property = $calendar->createProperty('RRULE', 'FREQ=YEARLY;COUNT=6;BYWEEKNO=55,2,-80;BYDAY=WE');
348        $result = $property->validate(Node::REPAIR);
349
350        $this->assertCount(2, $result);
351        $this->assertEquals('BYWEEKNO in RRULE must have value(s) from -53 to -1, or 1 to 53!', $result[0]['message']);
352        $this->assertEquals(1, $result[0]['level']);
353        $this->assertEquals('BYWEEKNO in RRULE must have value(s) from -53 to -1, or 1 to 53!', $result[1]['message']);
354        $this->assertEquals(1, $result[1]['level']);
355        $this->assertEquals('FREQ=YEARLY;COUNT=6;BYWEEKNO=2;BYDAY=WE', $property->getValue());
356
357    }
358
359    function testValidateAllInvalidByWeekNoWithRepair() {
360
361        $calendar = new VCalendar();
362        $property = $calendar->createProperty('RRULE', 'FREQ=YEARLY;COUNT=6;BYWEEKNO=55,-80;BYDAY=WE');
363        $result = $property->validate(Node::REPAIR);
364
365        $this->assertCount(2, $result);
366        $this->assertEquals('BYWEEKNO in RRULE must have value(s) from -53 to -1, or 1 to 53!', $result[0]['message']);
367        $this->assertEquals(1, $result[0]['level']);
368        $this->assertEquals('BYWEEKNO in RRULE must have value(s) from -53 to -1, or 1 to 53!', $result[1]['message']);
369        $this->assertEquals(1, $result[1]['level']);
370        $this->assertEquals('FREQ=YEARLY;COUNT=6;BYDAY=WE', $property->getValue());
371
372    }
373
374    function testValidateInvalidByWeekNoWithoutRepair() {
375
376        $calendar = new VCalendar();
377        $property = $calendar->createProperty('RRULE', 'FREQ=YEARLY;COUNT=6;BYWEEKNO=55;BYDAY=WE');
378        $result = $property->validate();
379
380        $this->assertCount(1, $result);
381        $this->assertEquals('BYWEEKNO in RRULE must have value(s) from -53 to -1, or 1 to 53!', $result[0]['message']);
382        $this->assertEquals(3, $result[0]['level']);
383        $this->assertEquals('FREQ=YEARLY;COUNT=6;BYWEEKNO=55;BYDAY=WE', $property->getValue());
384
385    }
386
387    function testValidateValidByYearDayWithRepair() {
388
389        $calendar = new VCalendar();
390        $property = $calendar->createProperty('RRULE', 'FREQ=YEARLY;COUNT=6;BYYEARDAY=119');
391        $result = $property->validate(Node::REPAIR);
392
393        $this->assertCount(0, $result);
394        $this->assertEquals('FREQ=YEARLY;COUNT=6;BYYEARDAY=119', $property->getValue());
395
396    }
397
398    function testValidateInvalidByYearDayWithRepair() {
399
400        $calendar = new VCalendar();
401        $property = $calendar->createProperty('RRULE', 'FREQ=YEARLY;COUNT=6;BYYEARDAY=367;BYDAY=WE');
402        $result = $property->validate(Node::REPAIR);
403
404        $this->assertCount(1, $result);
405        $this->assertEquals('BYYEARDAY in RRULE must have value(s) from -366 to -1, or 1 to 366!', $result[0]['message']);
406        $this->assertEquals(1, $result[0]['level']);
407        $this->assertEquals('FREQ=YEARLY;COUNT=6;BYDAY=WE', $property->getValue());
408
409    }
410
411    function testValidateMultipleInvalidByYearDayWithRepair() {
412
413        $calendar = new VCalendar();
414        $property = $calendar->createProperty('RRULE', 'FREQ=YEARLY;COUNT=6;BYYEARDAY=380,2,-390;BYDAY=WE');
415        $result = $property->validate(Node::REPAIR);
416
417        $this->assertCount(2, $result);
418        $this->assertEquals('BYYEARDAY in RRULE must have value(s) from -366 to -1, or 1 to 366!', $result[0]['message']);
419        $this->assertEquals(1, $result[0]['level']);
420        $this->assertEquals('BYYEARDAY in RRULE must have value(s) from -366 to -1, or 1 to 366!', $result[1]['message']);
421        $this->assertEquals(1, $result[1]['level']);
422        $this->assertEquals('FREQ=YEARLY;COUNT=6;BYYEARDAY=2;BYDAY=WE', $property->getValue());
423
424    }
425
426    function testValidateAllInvalidByYearDayWithRepair() {
427
428        $calendar = new VCalendar();
429        $property = $calendar->createProperty('RRULE', 'FREQ=YEARLY;COUNT=6;BYYEARDAY=455,-480;BYDAY=WE');
430        $result = $property->validate(Node::REPAIR);
431
432        $this->assertCount(2, $result);
433        $this->assertEquals('BYYEARDAY in RRULE must have value(s) from -366 to -1, or 1 to 366!', $result[0]['message']);
434        $this->assertEquals(1, $result[0]['level']);
435        $this->assertEquals('BYYEARDAY in RRULE must have value(s) from -366 to -1, or 1 to 366!', $result[1]['message']);
436        $this->assertEquals(1, $result[1]['level']);
437        $this->assertEquals('FREQ=YEARLY;COUNT=6;BYDAY=WE', $property->getValue());
438
439    }
440
441    function testValidateInvalidByYearDayWithoutRepair() {
442
443        $calendar = new VCalendar();
444        $property = $calendar->createProperty('RRULE', 'FREQ=YEARLY;COUNT=6;BYYEARDAY=380;BYDAY=WE');
445        $result = $property->validate();
446
447        $this->assertCount(1, $result);
448        $this->assertEquals('BYYEARDAY in RRULE must have value(s) from -366 to -1, or 1 to 366!', $result[0]['message']);
449        $this->assertEquals(3, $result[0]['level']);
450        $this->assertEquals('FREQ=YEARLY;COUNT=6;BYYEARDAY=380;BYDAY=WE', $property->getValue());
451
452    }
453}
454