1<?php 2 3namespace Sabre\VObject\Recur\EventIterator; 4 5use DateTime; 6use DateTimeZone; 7use Sabre\VObject\Recur\EventIterator; 8use Sabre\VObject\Component\VCalendar; 9 10class MainTest extends \PHPUnit_Framework_TestCase { 11 12 function testValues() { 13 14 $vcal = new VCalendar(); 15 $ev = $vcal->createComponent('VEVENT'); 16 $ev->UID = 'bla'; 17 $ev->RRULE = 'FREQ=DAILY;BYHOUR=10;BYMINUTE=5;BYSECOND=16;BYWEEKNO=32;BYYEARDAY=100,200'; 18 $dtStart = $vcal->createProperty('DTSTART'); 19 $dtStart->setDateTime(new DateTime('2011-10-07')); 20 21 $ev->add($dtStart); 22 23 $vcal->add($ev); 24 25 $it = new EventIterator($vcal,(string)$ev->uid); 26 27 $this->assertTrue($it->isInfinite()); 28 29 } 30 31 /** 32 * @expectedException InvalidArgumentException 33 * @depends testValues 34 */ 35 function testInvalidFreq() { 36 37 $vcal = new VCalendar(); 38 $ev = $vcal->createComponent('VEVENT'); 39 $ev->RRULE = 'FREQ=SMONTHLY;INTERVAL=3;UNTIL=20111025T000000Z'; 40 $ev->UID = 'foo'; 41 $dtStart = $vcal->createProperty('DTSTART'); 42 $dtStart->setDateTime(new DateTime('2011-10-07', new DateTimeZone('UTC'))); 43 44 $ev->add($dtStart); 45 $vcal->add($ev); 46 47 $it = new EventIterator($vcal,(string)$ev->uid); 48 49 } 50 51 /** 52 * @expectedException InvalidArgumentException 53 */ 54 function testVCalendarNoUID() { 55 56 $vcal = new VCalendar(); 57 $it = new EventIterator($vcal); 58 59 } 60 61 /** 62 * @expectedException InvalidArgumentException 63 */ 64 function testVCalendarInvalidUID() { 65 66 $vcal = new VCalendar(); 67 $it = new EventIterator($vcal,'foo'); 68 69 } 70 71 /** 72 * @depends testValues 73 */ 74 function testHourly() { 75 76 $vcal = new VCalendar(); 77 $ev = $vcal->createComponent('VEVENT'); 78 79 $ev->UID = 'bla'; 80 $ev->RRULE = 'FREQ=HOURLY;INTERVAL=3;UNTIL=20111025T000000Z'; 81 $dtStart = $vcal->createProperty('DTSTART'); 82 $dtStart->setDateTime(new DateTime('2011-10-07 12:00:00', new DateTimeZone('UTC'))); 83 84 $ev->add($dtStart); 85 $vcal->add($ev); 86 87 $it = new EventIterator($vcal,$ev->uid); 88 89 // Max is to prevent overflow 90 $max = 12; 91 $result = array(); 92 foreach($it as $item) { 93 94 $result[] = $item; 95 $max--; 96 97 if (!$max) break; 98 99 } 100 101 $tz = new DateTimeZone('UTC'); 102 103 $this->assertEquals( 104 array( 105 new DateTime('2011-10-07 12:00:00', $tz), 106 new DateTime('2011-10-07 15:00:00', $tz), 107 new DateTime('2011-10-07 18:00:00', $tz), 108 new DateTime('2011-10-07 21:00:00', $tz), 109 new DateTime('2011-10-08 00:00:00', $tz), 110 new DateTime('2011-10-08 03:00:00', $tz), 111 new DateTime('2011-10-08 06:00:00', $tz), 112 new DateTime('2011-10-08 09:00:00', $tz), 113 new DateTime('2011-10-08 12:00:00', $tz), 114 new DateTime('2011-10-08 15:00:00', $tz), 115 new DateTime('2011-10-08 18:00:00', $tz), 116 new DateTime('2011-10-08 21:00:00', $tz), 117 ), 118 $result 119 ); 120 121 } 122 123 /** 124 * @depends testValues 125 */ 126 function testDaily() { 127 128 $vcal = new VCalendar(); 129 $ev = $vcal->createComponent('VEVENT'); 130 131 $ev->UID = 'bla'; 132 $ev->RRULE = 'FREQ=DAILY;INTERVAL=3;UNTIL=20111025T000000Z'; 133 $dtStart = $vcal->createProperty('DTSTART'); 134 $dtStart->setDateTime(new DateTime('2011-10-07', new DateTimeZone('UTC'))); 135 136 $ev->add($dtStart); 137 138 $vcal->add($ev); 139 140 $it = new EventIterator($vcal,$ev->uid); 141 142 // Max is to prevent overflow 143 $max = 12; 144 $result = array(); 145 foreach($it as $item) { 146 147 $result[] = $item; 148 $max--; 149 150 if (!$max) break; 151 152 } 153 154 $tz = new DateTimeZone('UTC'); 155 156 $this->assertEquals( 157 array( 158 new DateTime('2011-10-07', $tz), 159 new DateTime('2011-10-10', $tz), 160 new DateTime('2011-10-13', $tz), 161 new DateTime('2011-10-16', $tz), 162 new DateTime('2011-10-19', $tz), 163 new DateTime('2011-10-22', $tz), 164 new DateTime('2011-10-25', $tz), 165 ), 166 $result 167 ); 168 169 } 170 171 /** 172 * @depends testValues 173 */ 174 function testNoRRULE() { 175 176 $vcal = new VCalendar(); 177 $ev = $vcal->createComponent('VEVENT'); 178 179 $ev->UID = 'bla'; 180 $dtStart = $vcal->createProperty('DTSTART'); 181 $dtStart->setDateTime(new DateTime('2011-10-07', new DateTimeZone('UTC'))); 182 183 $ev->add($dtStart); 184 185 $vcal->add($ev); 186 187 $it = new EventIterator($vcal,$ev->uid); 188 189 // Max is to prevent overflow 190 $max = 12; 191 $result = array(); 192 foreach($it as $item) { 193 194 $result[] = $item; 195 $max--; 196 197 if (!$max) break; 198 199 } 200 201 $tz = new DateTimeZone('UTC'); 202 203 $this->assertEquals( 204 array( 205 new DateTime('2011-10-07', $tz), 206 ), 207 $result 208 ); 209 210 } 211 212 /** 213 * @depends testValues 214 */ 215 function testDailyByDayByHour() { 216 217 $vcal = new VCalendar(); 218 $ev = $vcal->createComponent('VEVENT'); 219 220 $ev->UID = 'bla'; 221 $ev->RRULE = 'FREQ=DAILY;BYDAY=SA,SU;BYHOUR=6,7'; 222 $dtStart = $vcal->createProperty('DTSTART'); 223 $dtStart->setDateTime(new DateTime('2011-10-08 06:00:00', new DateTimeZone('UTC'))); 224 225 $ev->add($dtStart); 226 227 $vcal->add($ev); 228 229 $it = new EventIterator($vcal,(string)$ev->uid); 230 231 // Grabbing the next 12 items 232 $max = 12; 233 $result = array(); 234 foreach($it as $item) { 235 236 $result[] = $item; 237 $max--; 238 239 if (!$max) break; 240 241 } 242 243 $tz = new DateTimeZone('UTC'); 244 245 $this->assertEquals( 246 array( 247 new datetime('2011-10-08 06:00:00', $tz), 248 new datetime('2011-10-08 07:00:00', $tz), 249 new datetime('2011-10-09 06:00:00', $tz), 250 new datetime('2011-10-09 07:00:00', $tz), 251 new datetime('2011-10-15 06:00:00', $tz), 252 new datetime('2011-10-15 07:00:00', $tz), 253 new datetime('2011-10-16 06:00:00', $tz), 254 new datetime('2011-10-16 07:00:00', $tz), 255 new datetime('2011-10-22 06:00:00', $tz), 256 new datetime('2011-10-22 07:00:00', $tz), 257 new datetime('2011-10-23 06:00:00', $tz), 258 new datetime('2011-10-23 07:00:00', $tz), 259 ), 260 $result 261 ); 262 263 } 264 265 /** 266 * @depends testValues 267 */ 268 function testDailyByHour() { 269 270 $vcal = new VCalendar(); 271 $ev = $vcal->createComponent('VEVENT'); 272 273 $ev->UID = 'bla'; 274 $ev->RRULE = 'FREQ=DAILY;INTERVAL=2;BYHOUR=10,11,12,13,14,15'; 275 $dtStart = $vcal->createProperty('DTSTART'); 276 $dtStart->setDateTime(new DateTime('2012-10-11 12:00:00', new DateTimeZone('UTC'))); 277 278 $ev->add($dtStart); 279 280 $vcal->add($ev); 281 282 $it = new EventIterator($vcal,(string)$ev->uid); 283 284 // Grabbing the next 12 items 285 $max = 12; 286 $result = array(); 287 foreach($it as $item) { 288 289 $result[] = $item; 290 $max--; 291 292 if (!$max) break; 293 294 } 295 296 $tz = new DateTimeZone('UTC'); 297 298 $this->assertEquals( 299 array( 300 new datetime('2012-10-11 12:00:00', $tz), 301 new datetime('2012-10-11 13:00:00', $tz), 302 new datetime('2012-10-11 14:00:00', $tz), 303 new datetime('2012-10-11 15:00:00', $tz), 304 new datetime('2012-10-13 10:00:00', $tz), 305 new datetime('2012-10-13 11:00:00', $tz), 306 new datetime('2012-10-13 12:00:00', $tz), 307 new datetime('2012-10-13 13:00:00', $tz), 308 new datetime('2012-10-13 14:00:00', $tz), 309 new datetime('2012-10-13 15:00:00', $tz), 310 new datetime('2012-10-15 10:00:00', $tz), 311 new datetime('2012-10-15 11:00:00', $tz), 312 ), 313 $result 314 ); 315 316 } 317 318 /** 319 * @depends testValues 320 */ 321 function testDailyByDay() { 322 323 $vcal = new VCalendar(); 324 $ev = $vcal->createComponent('VEVENT'); 325 326 $ev->UID = 'bla'; 327 $ev->RRULE = 'FREQ=DAILY;INTERVAL=2;BYDAY=TU,WE,FR'; 328 $dtStart = $vcal->createProperty('DTSTART'); 329 $dtStart->setDateTime(new DateTime('2011-10-07', new DateTimeZone('UTC'))); 330 331 $ev->add($dtStart); 332 333 $vcal->add($ev); 334 335 $it = new EventIterator($vcal,(string)$ev->uid); 336 337 // Grabbing the next 12 items 338 $max = 12; 339 $result = array(); 340 foreach($it as $item) { 341 342 $result[] = $item; 343 $max--; 344 345 if (!$max) break; 346 347 } 348 349 $tz = new DateTimeZone('UTC'); 350 351 $this->assertEquals( 352 array( 353 new DateTime('2011-10-07', $tz), 354 new DateTime('2011-10-11', $tz), 355 new DateTime('2011-10-19', $tz), 356 new DateTime('2011-10-21', $tz), 357 new DateTime('2011-10-25', $tz), 358 new DateTime('2011-11-02', $tz), 359 new DateTime('2011-11-04', $tz), 360 new DateTime('2011-11-08', $tz), 361 new DateTime('2011-11-16', $tz), 362 new DateTime('2011-11-18', $tz), 363 new DateTime('2011-11-22', $tz), 364 new DateTime('2011-11-30', $tz), 365 ), 366 $result 367 ); 368 369 } 370 371 /** 372 * @depends testValues 373 */ 374 function testWeekly() { 375 376 $vcal = new VCalendar(); 377 $ev = $vcal->createComponent('VEVENT'); 378 379 $ev->UID = 'bla'; 380 $ev->RRULE = 'FREQ=WEEKLY;INTERVAL=2;COUNT=10'; 381 $dtStart = $vcal->createProperty('DTSTART'); 382 $dtStart->setDateTime(new DateTime('2011-10-07', new DateTimeZone('UTC'))); 383 384 $ev->add($dtStart); 385 386 $vcal->add($ev); 387 388 $it = new EventIterator($vcal,(string)$ev->uid); 389 390 // Max is to prevent overflow 391 $max = 12; 392 $result = array(); 393 foreach($it as $item) { 394 395 $result[] = $item; 396 $max--; 397 398 if (!$max) break; 399 400 } 401 402 $tz = new DateTimeZone('UTC'); 403 404 $this->assertEquals( 405 array( 406 new DateTime('2011-10-07', $tz), 407 new DateTime('2011-10-21', $tz), 408 new DateTime('2011-11-04', $tz), 409 new DateTime('2011-11-18', $tz), 410 new DateTime('2011-12-02', $tz), 411 new DateTime('2011-12-16', $tz), 412 new DateTime('2011-12-30', $tz), 413 new DateTime('2012-01-13', $tz), 414 new DateTime('2012-01-27', $tz), 415 new DateTime('2012-02-10', $tz), 416 ), 417 $result 418 ); 419 420 } 421 422 /** 423 * @depends testValues 424 */ 425 function testWeeklyByDayByHour() { 426 427 $vcal = new VCalendar(); 428 $ev = $vcal->createComponent('VEVENT'); 429 430 $ev->UID = 'bla'; 431 $ev->RRULE = 'FREQ=WEEKLY;INTERVAL=2;BYDAY=TU,WE,FR;WKST=MO;BYHOUR=8,9,10'; 432 $dtStart = $vcal->createProperty('DTSTART'); 433 $dtStart->setDateTime(new DateTime('2011-10-07 08:00:00', new DateTimeZone('UTC'))); 434 435 $ev->add($dtStart); 436 437 $vcal->add($ev); 438 439 $it = new EventIterator($vcal,(string)$ev->uid); 440 441 // Grabbing the next 12 items 442 $max = 15; 443 $result = array(); 444 foreach($it as $item) { 445 446 $result[] = $item; 447 $max--; 448 449 if (!$max) break; 450 451 } 452 453 $tz = new DateTimeZone('UTC'); 454 455 $this->assertEquals( 456 array( 457 new DateTime('2011-10-07 08:00:00', $tz), 458 new DateTime('2011-10-07 09:00:00', $tz), 459 new DateTime('2011-10-07 10:00:00', $tz), 460 new DateTime('2011-10-18 08:00:00', $tz), 461 new DateTime('2011-10-18 09:00:00', $tz), 462 new DateTime('2011-10-18 10:00:00', $tz), 463 new DateTime('2011-10-19 08:00:00', $tz), 464 new DateTime('2011-10-19 09:00:00', $tz), 465 new DateTime('2011-10-19 10:00:00', $tz), 466 new DateTime('2011-10-21 08:00:00', $tz), 467 new DateTime('2011-10-21 09:00:00', $tz), 468 new DateTime('2011-10-21 10:00:00', $tz), 469 new DateTime('2011-11-01 08:00:00', $tz), 470 new DateTime('2011-11-01 09:00:00', $tz), 471 new DateTime('2011-11-01 10:00:00', $tz), 472 ), 473 $result 474 ); 475 476 } 477 478 /** 479 * @depends testValues 480 */ 481 function testWeeklyByDaySpecificHour() { 482 483 $vcal = new VCalendar(); 484 $ev = $vcal->createComponent('VEVENT'); 485 486 $ev->UID = 'bla'; 487 $ev->RRULE = 'FREQ=WEEKLY;INTERVAL=2;BYDAY=TU,WE,FR;WKST=SU'; 488 $dtStart = $vcal->createProperty('DTSTART'); 489 $dtStart->setDateTime(new DateTime('2011-10-07 18:00:00', new DateTimeZone('UTC'))); 490 491 $ev->add($dtStart); 492 493 $vcal->add($ev); 494 495 $it = new EventIterator($vcal,(string)$ev->uid); 496 497 // Grabbing the next 12 items 498 $max = 12; 499 $result = array(); 500 foreach($it as $item) { 501 502 $result[] = $item; 503 $max--; 504 505 if (!$max) break; 506 507 } 508 509 $tz = new DateTimeZone('UTC'); 510 511 $this->assertEquals( 512 array( 513 new DateTime('2011-10-07 18:00:00', $tz), 514 new DateTime('2011-10-18 18:00:00', $tz), 515 new DateTime('2011-10-19 18:00:00', $tz), 516 new DateTime('2011-10-21 18:00:00', $tz), 517 new DateTime('2011-11-01 18:00:00', $tz), 518 new DateTime('2011-11-02 18:00:00', $tz), 519 new DateTime('2011-11-04 18:00:00', $tz), 520 new DateTime('2011-11-15 18:00:00', $tz), 521 new DateTime('2011-11-16 18:00:00', $tz), 522 new DateTime('2011-11-18 18:00:00', $tz), 523 new DateTime('2011-11-29 18:00:00', $tz), 524 new DateTime('2011-11-30 18:00:00', $tz), 525 ), 526 $result 527 ); 528 529 } 530 531 /** 532 * @depends testValues 533 */ 534 function testWeeklyByDay() { 535 536 $vcal = new VCalendar(); 537 $ev = $vcal->createComponent('VEVENT'); 538 539 $ev->UID = 'bla'; 540 $ev->RRULE = 'FREQ=WEEKLY;INTERVAL=2;BYDAY=TU,WE,FR;WKST=SU'; 541 $dtStart = $vcal->createProperty('DTSTART'); 542 $dtStart->setDateTime(new DateTime('2011-10-07', new DateTimeZone('UTC'))); 543 544 $ev->add($dtStart); 545 546 $vcal->add($ev); 547 548 $it = new EventIterator($vcal,(string)$ev->uid); 549 550 // Grabbing the next 12 items 551 $max = 12; 552 $result = array(); 553 foreach($it as $item) { 554 555 $result[] = $item; 556 $max--; 557 558 if (!$max) break; 559 560 } 561 562 $tz = new DateTimeZone('UTC'); 563 564 $this->assertEquals( 565 array( 566 new DateTime('2011-10-07', $tz), 567 new DateTime('2011-10-18', $tz), 568 new DateTime('2011-10-19', $tz), 569 new DateTime('2011-10-21', $tz), 570 new DateTime('2011-11-01', $tz), 571 new DateTime('2011-11-02', $tz), 572 new DateTime('2011-11-04', $tz), 573 new DateTime('2011-11-15', $tz), 574 new DateTime('2011-11-16', $tz), 575 new DateTime('2011-11-18', $tz), 576 new DateTime('2011-11-29', $tz), 577 new DateTime('2011-11-30', $tz), 578 ), 579 $result 580 ); 581 582 } 583 584 /** 585 * @depends testValues 586 */ 587 function testMonthly() { 588 589 $vcal = new VCalendar(); 590 $ev = $vcal->createComponent('VEVENT'); 591 592 $ev->UID = 'bla'; 593 $ev->RRULE = 'FREQ=MONTHLY;INTERVAL=3;COUNT=5'; 594 $dtStart = $vcal->createProperty('DTSTART'); 595 $dtStart->setDateTime(new DateTime('2011-12-05', new DateTimeZone('UTC'))); 596 597 $ev->add($dtStart); 598 599 $vcal->add($ev); 600 601 $it = new EventIterator($vcal,(string)$ev->uid); 602 603 $max = 14; 604 $result = array(); 605 foreach($it as $item) { 606 607 $result[] = $item; 608 $max--; 609 610 if (!$max) break; 611 612 } 613 614 $tz = new DateTimeZone('UTC'); 615 616 $this->assertEquals( 617 array( 618 new DateTime('2011-12-05', $tz), 619 new DateTime('2012-03-05', $tz), 620 new DateTime('2012-06-05', $tz), 621 new DateTime('2012-09-05', $tz), 622 new DateTime('2012-12-05', $tz), 623 ), 624 $result 625 ); 626 627 628 } 629 630 /** 631 * @depends testValues 632 */ 633 function testMonthlyEndOfMonth() { 634 635 $vcal = new VCalendar(); 636 $ev = $vcal->createComponent('VEVENT'); 637 638 $ev->UID = 'bla'; 639 $ev->RRULE = 'FREQ=MONTHLY;INTERVAL=2;COUNT=12'; 640 $dtStart = $vcal->createProperty('DTSTART'); 641 $dtStart->setDateTime(new DateTime('2011-12-31', new DateTimeZone('UTC'))); 642 643 $ev->add($dtStart); 644 645 $vcal->add($ev); 646 647 $it = new EventIterator($vcal,(string)$ev->uid); 648 649 $max = 14; 650 $result = array(); 651 foreach($it as $item) { 652 653 $result[] = $item; 654 $max--; 655 656 if (!$max) break; 657 658 } 659 660 $tz = new DateTimeZone('UTC'); 661 662 $this->assertEquals( 663 array( 664 new DateTime('2011-12-31', $tz), 665 new DateTime('2012-08-31', $tz), 666 new DateTime('2012-10-31', $tz), 667 new DateTime('2012-12-31', $tz), 668 new DateTime('2013-08-31', $tz), 669 new DateTime('2013-10-31', $tz), 670 new DateTime('2013-12-31', $tz), 671 new DateTime('2014-08-31', $tz), 672 new DateTime('2014-10-31', $tz), 673 new DateTime('2014-12-31', $tz), 674 new DateTime('2015-08-31', $tz), 675 new DateTime('2015-10-31', $tz), 676 ), 677 $result 678 ); 679 680 681 } 682 683 /** 684 * @depends testValues 685 */ 686 function testMonthlyByMonthDay() { 687 688 $vcal = new VCalendar(); 689 $ev = $vcal->createComponent('VEVENT'); 690 691 $ev->UID = 'bla'; 692 $ev->RRULE = 'FREQ=MONTHLY;INTERVAL=5;COUNT=9;BYMONTHDAY=1,31,-7'; 693 $dtStart = $vcal->createProperty('DTSTART'); 694 $dtStart->setDateTime(new DateTime('2011-01-01', new DateTimeZone('UTC'))); 695 696 $ev->add($dtStart); 697 698 $vcal->add($ev); 699 700 $it = new EventIterator($vcal,(string)$ev->uid); 701 702 $max = 14; 703 $result = array(); 704 foreach($it as $item) { 705 706 $result[] = $item; 707 $max--; 708 709 if (!$max) break; 710 711 } 712 713 $tz = new DateTimeZone('UTC'); 714 715 $this->assertEquals( 716 array( 717 new DateTime('2011-01-01', $tz), 718 new DateTime('2011-01-25', $tz), 719 new DateTime('2011-01-31', $tz), 720 new DateTime('2011-06-01', $tz), 721 new DateTime('2011-06-24', $tz), 722 new DateTime('2011-11-01', $tz), 723 new DateTime('2011-11-24', $tz), 724 new DateTime('2012-04-01', $tz), 725 new DateTime('2012-04-24', $tz), 726 ), 727 $result 728 ); 729 730 } 731 732 /** 733 * A pretty slow test. Had to be marked as 'medium' for phpunit to not die 734 * after 1 second. Would be good to optimize later. 735 * 736 * @depends testValues 737 * @medium 738 */ 739 function testMonthlyByDay() { 740 741 $vcal = new VCalendar(); 742 $ev = $vcal->createComponent('VEVENT'); 743 744 $ev->UID = 'bla'; 745 $ev->RRULE = 'FREQ=MONTHLY;INTERVAL=2;COUNT=16;BYDAY=MO,-2TU,+1WE,3TH'; 746 $dtStart = $vcal->createProperty('DTSTART'); 747 $dtStart->setDateTime(new DateTime('2011-01-03', new DateTimeZone('UTC'))); 748 749 $ev->add($dtStart); 750 751 $vcal->add($ev); 752 753 $it = new EventIterator($vcal,(string)$ev->uid); 754 755 $max = 20; 756 $result = array(); 757 foreach($it as $k=>$item) { 758 759 $result[] = $item; 760 $max--; 761 762 if (!$max) break; 763 764 } 765 766 $tz = new DateTimeZone('UTC'); 767 768 $this->assertEquals( 769 array( 770 new DateTime('2011-01-03', $tz), 771 new DateTime('2011-01-05', $tz), 772 new DateTime('2011-01-10', $tz), 773 new DateTime('2011-01-17', $tz), 774 new DateTime('2011-01-18', $tz), 775 new DateTime('2011-01-20', $tz), 776 new DateTime('2011-01-24', $tz), 777 new DateTime('2011-01-31', $tz), 778 new DateTime('2011-03-02', $tz), 779 new DateTime('2011-03-07', $tz), 780 new DateTime('2011-03-14', $tz), 781 new DateTime('2011-03-17', $tz), 782 new DateTime('2011-03-21', $tz), 783 new DateTime('2011-03-22', $tz), 784 new DateTime('2011-03-28', $tz), 785 new DateTime('2011-05-02', $tz), 786 ), 787 $result 788 ); 789 790 } 791 792 /** 793 * @depends testValues 794 */ 795 function testMonthlyByDayByMonthDay() { 796 797 $vcal = new VCalendar(); 798 $ev = $vcal->createComponent('VEVENT'); 799 800 $ev->UID = 'bla'; 801 $ev->RRULE = 'FREQ=MONTHLY;COUNT=10;BYDAY=MO;BYMONTHDAY=1'; 802 $dtStart = $vcal->createProperty('DTSTART'); 803 $dtStart->setDateTime(new DateTime('2011-08-01', new DateTimeZone('UTC'))); 804 805 $ev->add($dtStart); 806 807 $vcal->add($ev); 808 809 $it = new EventIterator($vcal,(string)$ev->uid); 810 811 $max = 20; 812 $result = array(); 813 foreach($it as $k=>$item) { 814 815 $result[] = $item; 816 $max--; 817 818 if (!$max) break; 819 820 } 821 822 $tz = new DateTimeZone('UTC'); 823 824 $this->assertEquals( 825 array( 826 new DateTime('2011-08-01', $tz), 827 new DateTime('2012-10-01', $tz), 828 new DateTime('2013-04-01', $tz), 829 new DateTime('2013-07-01', $tz), 830 new DateTime('2014-09-01', $tz), 831 new DateTime('2014-12-01', $tz), 832 new DateTime('2015-06-01', $tz), 833 new DateTime('2016-02-01', $tz), 834 new DateTime('2016-08-01', $tz), 835 new DateTime('2017-05-01', $tz), 836 ), 837 $result 838 ); 839 840 } 841 842 /** 843 * @depends testValues 844 */ 845 function testMonthlyByDayBySetPos() { 846 847 $vcal = new VCalendar(); 848 $ev = $vcal->createComponent('VEVENT'); 849 850 $ev->UID = 'bla'; 851 $ev->RRULE = 'FREQ=MONTHLY;COUNT=10;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=1,-1'; 852 $dtStart = $vcal->createProperty('DTSTART'); 853 $dtStart->setDateTime(new DateTime('2011-01-03', new DateTimeZone('UTC'))); 854 855 $ev->add($dtStart); 856 857 $vcal->add($ev); 858 859 $it = new EventIterator($vcal,(string)$ev->uid); 860 861 $max = 20; 862 $result = array(); 863 foreach($it as $k=>$item) { 864 865 $result[] = $item; 866 $max--; 867 868 if (!$max) break; 869 870 } 871 872 $tz = new DateTimeZone('UTC'); 873 874 $this->assertEquals( 875 array( 876 new DateTime('2011-01-03', $tz), 877 new DateTime('2011-01-31', $tz), 878 new DateTime('2011-02-01', $tz), 879 new DateTime('2011-02-28', $tz), 880 new DateTime('2011-03-01', $tz), 881 new DateTime('2011-03-31', $tz), 882 new DateTime('2011-04-01', $tz), 883 new DateTime('2011-04-29', $tz), 884 new DateTime('2011-05-02', $tz), 885 new DateTime('2011-05-31', $tz), 886 ), 887 $result 888 ); 889 890 } 891 892 /** 893 * @depends testValues 894 */ 895 function testYearly() { 896 897 $vcal = new VCalendar(); 898 $ev = $vcal->createComponent('VEVENT'); 899 900 $ev->UID = 'bla'; 901 $ev->RRULE = 'FREQ=YEARLY;COUNT=10;INTERVAL=3'; 902 $dtStart = $vcal->createProperty('DTSTART'); 903 $dtStart->setDateTime(new DateTime('2011-01-01', new DateTimeZone('UTC'))); 904 905 $ev->add($dtStart); 906 907 $vcal->add($ev); 908 909 $it = new EventIterator($vcal,(string)$ev->uid); 910 911 $max = 20; 912 $result = array(); 913 foreach($it as $k=>$item) { 914 915 $result[] = $item; 916 $max--; 917 918 if (!$max) break; 919 920 } 921 922 $tz = new DateTimeZone('UTC'); 923 924 $this->assertEquals( 925 array( 926 new DateTime('2011-01-01', $tz), 927 new DateTime('2014-01-01', $tz), 928 new DateTime('2017-01-01', $tz), 929 new DateTime('2020-01-01', $tz), 930 new DateTime('2023-01-01', $tz), 931 new DateTime('2026-01-01', $tz), 932 new DateTime('2029-01-01', $tz), 933 new DateTime('2032-01-01', $tz), 934 new DateTime('2035-01-01', $tz), 935 new DateTime('2038-01-01', $tz), 936 ), 937 $result 938 ); 939 940 } 941 942 /** 943 * @depends testValues 944 */ 945 function testYearlyLeapYear() { 946 947 $vcal = new VCalendar(); 948 $ev = $vcal->createComponent('VEVENT'); 949 950 $ev->UID = 'bla'; 951 $ev->RRULE = 'FREQ=YEARLY;COUNT=3'; 952 $dtStart = $vcal->createProperty('DTSTART'); 953 $dtStart->setDateTime(new DateTime('2012-02-29', new DateTimeZone('UTC'))); 954 955 $ev->add($dtStart); 956 957 $vcal->add($ev); 958 959 $it = new EventIterator($vcal,(string)$ev->uid); 960 961 $max = 20; 962 $result = array(); 963 foreach($it as $k=>$item) { 964 965 $result[] = $item; 966 $max--; 967 968 if (!$max) break; 969 970 } 971 972 $tz = new DateTimeZone('UTC'); 973 974 $this->assertEquals( 975 array( 976 new DateTime('2012-02-29', $tz), 977 new DateTime('2016-02-29', $tz), 978 new DateTime('2020-02-29', $tz), 979 ), 980 $result 981 ); 982 983 } 984 985 /** 986 * @depends testValues 987 */ 988 function testYearlyByMonth() { 989 990 $vcal = new VCalendar(); 991 $ev = $vcal->createComponent('VEVENT'); 992 993 $ev->UID = 'bla'; 994 $ev->RRULE = 'FREQ=YEARLY;COUNT=8;INTERVAL=4;BYMONTH=4,10'; 995 $dtStart = $vcal->createProperty('DTSTART'); 996 $dtStart->setDateTime(new DateTime('2011-04-07', new DateTimeZone('UTC'))); 997 998 $ev->add($dtStart); 999 1000 $vcal->add($ev); 1001 1002 $it = new EventIterator($vcal,(string)$ev->uid); 1003 1004 $max = 20; 1005 $result = array(); 1006 foreach($it as $k=>$item) { 1007 1008 $result[] = $item; 1009 $max--; 1010 1011 if (!$max) break; 1012 1013 } 1014 1015 $tz = new DateTimeZone('UTC'); 1016 1017 $this->assertEquals( 1018 array( 1019 new DateTime('2011-04-07', $tz), 1020 new DateTime('2011-10-07', $tz), 1021 new DateTime('2015-04-07', $tz), 1022 new DateTime('2015-10-07', $tz), 1023 new DateTime('2019-04-07', $tz), 1024 new DateTime('2019-10-07', $tz), 1025 new DateTime('2023-04-07', $tz), 1026 new DateTime('2023-10-07', $tz), 1027 ), 1028 $result 1029 ); 1030 1031 } 1032 1033 /** 1034 * @depends testValues 1035 */ 1036 function testYearlyByMonthByDay() { 1037 1038 $vcal = new VCalendar(); 1039 $ev = $vcal->createComponent('VEVENT'); 1040 1041 $ev->UID = 'bla'; 1042 $ev->RRULE = 'FREQ=YEARLY;COUNT=8;INTERVAL=5;BYMONTH=4,10;BYDAY=1MO,-1SU'; 1043 $dtStart = $vcal->createProperty('DTSTART'); 1044 $dtStart->setDateTime(new DateTime('2011-04-04', new DateTimeZone('UTC'))); 1045 1046 $ev->add($dtStart); 1047 1048 $vcal->add($ev); 1049 1050 $it = new EventIterator($vcal,(string)$ev->uid); 1051 1052 $max = 20; 1053 $result = array(); 1054 foreach($it as $k=>$item) { 1055 1056 $result[] = $item; 1057 $max--; 1058 1059 if (!$max) break; 1060 1061 } 1062 1063 $tz = new DateTimeZone('UTC'); 1064 1065 $this->assertEquals( 1066 array( 1067 new DateTime('2011-04-04', $tz), 1068 new DateTime('2011-04-24', $tz), 1069 new DateTime('2011-10-03', $tz), 1070 new DateTime('2011-10-30', $tz), 1071 new DateTime('2016-04-04', $tz), 1072 new DateTime('2016-04-24', $tz), 1073 new DateTime('2016-10-03', $tz), 1074 new DateTime('2016-10-30', $tz), 1075 ), 1076 $result 1077 ); 1078 1079 } 1080 1081 /** 1082 * @depends testValues 1083 */ 1084 function testFastForward() { 1085 1086 $vcal = new VCalendar(); 1087 $ev = $vcal->createComponent('VEVENT'); 1088 1089 $ev->UID = 'bla'; 1090 $ev->RRULE = 'FREQ=YEARLY;COUNT=8;INTERVAL=5;BYMONTH=4,10;BYDAY=1MO,-1SU'; 1091 $dtStart = $vcal->createProperty('DTSTART'); 1092 $dtStart->setDateTime(new DateTime('2011-04-04', new DateTimeZone('UTC'))); 1093 1094 $ev->add($dtStart); 1095 1096 $vcal->add($ev); 1097 1098 $it = new EventIterator($vcal,(string)$ev->uid); 1099 1100 // The idea is that we're fast-forwarding too far in the future, so 1101 // there will be no results left. 1102 $it->fastForward(new DateTime('2020-05-05', new DateTimeZone('UTC'))); 1103 1104 $max = 20; 1105 $result = array(); 1106 while($item = $it->current()) { 1107 1108 $result[] = $item; 1109 $max--; 1110 1111 if (!$max) break; 1112 $it->next(); 1113 1114 } 1115 1116 $tz = new DateTimeZone('UTC'); 1117 $this->assertEquals(array(), $result); 1118 1119 } 1120 1121 /** 1122 * @depends testValues 1123 */ 1124 function testComplexExclusions() { 1125 1126 $vcal = new VCalendar(); 1127 $ev = $vcal->createComponent('VEVENT'); 1128 1129 $ev->UID = 'bla'; 1130 $ev->RRULE = 'FREQ=YEARLY;COUNT=10'; 1131 $dtStart = $vcal->createProperty('DTSTART'); 1132 1133 $tz = new DateTimeZone('Canada/Eastern'); 1134 $dtStart->setDateTime(new DateTime('2011-01-01 13:50:20', $tz)); 1135 1136 $exDate1 = $vcal->createProperty('EXDATE'); 1137 $exDate1->setDateTimes(array(new DateTime('2012-01-01 13:50:20', $tz), new DateTime('2014-01-01 13:50:20', $tz))); 1138 $exDate2 = $vcal->createProperty('EXDATE'); 1139 $exDate2->setDateTimes(array(new DateTime('2016-01-01 13:50:20', $tz))); 1140 1141 $ev->add($dtStart); 1142 $ev->add($exDate1); 1143 $ev->add($exDate2); 1144 1145 $vcal->add($ev); 1146 1147 $it = new EventIterator($vcal,(string)$ev->uid); 1148 1149 $max = 20; 1150 $result = array(); 1151 foreach($it as $k=>$item) { 1152 1153 $result[] = $item; 1154 $max--; 1155 1156 if (!$max) break; 1157 1158 } 1159 1160 $this->assertEquals( 1161 array( 1162 new DateTime('2011-01-01 13:50:20', $tz), 1163 new DateTime('2013-01-01 13:50:20', $tz), 1164 new DateTime('2015-01-01 13:50:20', $tz), 1165 new DateTime('2017-01-01 13:50:20', $tz), 1166 new DateTime('2018-01-01 13:50:20', $tz), 1167 new DateTime('2019-01-01 13:50:20', $tz), 1168 new DateTime('2020-01-01 13:50:20', $tz), 1169 ), 1170 $result 1171 ); 1172 1173 } 1174 1175 /** 1176 * @depends testValues 1177 */ 1178 function testOverridenEvent() { 1179 1180 $vcal = new VCalendar(); 1181 1182 $ev1 = $vcal->createComponent('VEVENT'); 1183 $ev1->UID = 'overridden'; 1184 $ev1->RRULE = 'FREQ=DAILY;COUNT=10'; 1185 $ev1->DTSTART = '20120107T120000Z'; 1186 $ev1->SUMMARY = 'baseEvent'; 1187 1188 $vcal->add($ev1); 1189 1190 // ev2 overrides an event, and puts it on 2pm instead. 1191 $ev2 = $vcal->createComponent('VEVENT'); 1192 $ev2->UID = 'overridden'; 1193 $ev2->{'RECURRENCE-ID'} = '20120110T120000Z'; 1194 $ev2->DTSTART = '20120110T140000Z'; 1195 $ev2->SUMMARY = 'Event 2'; 1196 1197 $vcal->add($ev2); 1198 1199 // ev3 overrides an event, and puts it 2 days and 2 hours later 1200 $ev3 = $vcal->createComponent('VEVENT'); 1201 $ev3->UID = 'overridden'; 1202 $ev3->{'RECURRENCE-ID'} = '20120113T120000Z'; 1203 $ev3->DTSTART = '20120115T140000Z'; 1204 $ev3->SUMMARY = 'Event 3'; 1205 1206 $vcal->add($ev3); 1207 1208 $it = new EventIterator($vcal,'overridden'); 1209 1210 $dates = array(); 1211 $summaries = array(); 1212 while($it->valid()) { 1213 1214 $dates[] = $it->getDTStart(); 1215 $summaries[] = (string)$it->getEventObject()->SUMMARY; 1216 $it->next(); 1217 1218 } 1219 1220 $tz = new DateTimeZone('UTC'); 1221 $this->assertEquals(array( 1222 new DateTime('2012-01-07 12:00:00',$tz), 1223 new DateTime('2012-01-08 12:00:00',$tz), 1224 new DateTime('2012-01-09 12:00:00',$tz), 1225 new DateTime('2012-01-10 14:00:00',$tz), 1226 new DateTime('2012-01-11 12:00:00',$tz), 1227 new DateTime('2012-01-12 12:00:00',$tz), 1228 new DateTime('2012-01-14 12:00:00',$tz), 1229 new DateTime('2012-01-15 12:00:00',$tz), 1230 new DateTime('2012-01-15 14:00:00',$tz), 1231 new DateTime('2012-01-16 12:00:00',$tz), 1232 ), $dates); 1233 1234 $this->assertEquals(array( 1235 'baseEvent', 1236 'baseEvent', 1237 'baseEvent', 1238 'Event 2', 1239 'baseEvent', 1240 'baseEvent', 1241 'baseEvent', 1242 'baseEvent', 1243 'Event 3', 1244 'baseEvent', 1245 ), $summaries); 1246 1247 } 1248 1249 /** 1250 * @depends testValues 1251 */ 1252 function testOverridenEvent2() { 1253 1254 $vcal = new VCalendar(); 1255 1256 $ev1 = $vcal->createComponent('VEVENT'); 1257 $ev1->UID = 'overridden'; 1258 $ev1->RRULE = 'FREQ=WEEKLY;COUNT=3'; 1259 $ev1->DTSTART = '20120112T120000Z'; 1260 $ev1->SUMMARY = 'baseEvent'; 1261 1262 $vcal->add($ev1); 1263 1264 // ev2 overrides an event, and puts it 6 days earlier instead. 1265 $ev2 = $vcal->createComponent('VEVENT'); 1266 $ev2->UID = 'overridden'; 1267 $ev2->{'RECURRENCE-ID'} = '20120119T120000Z'; 1268 $ev2->DTSTART = '20120113T120000Z'; 1269 $ev2->SUMMARY = 'Override!'; 1270 1271 $vcal->add($ev2); 1272 1273 $it = new EventIterator($vcal,'overridden'); 1274 1275 $dates = array(); 1276 $summaries = array(); 1277 while($it->valid()) { 1278 1279 $dates[] = $it->getDTStart(); 1280 $summaries[] = (string)$it->getEventObject()->SUMMARY; 1281 $it->next(); 1282 1283 } 1284 1285 $tz = new DateTimeZone('UTC'); 1286 $this->assertEquals(array( 1287 new DateTime('2012-01-12 12:00:00',$tz), 1288 new DateTime('2012-01-13 12:00:00',$tz), 1289 new DateTime('2012-01-26 12:00:00',$tz), 1290 1291 ), $dates); 1292 1293 $this->assertEquals(array( 1294 'baseEvent', 1295 'Override!', 1296 'baseEvent', 1297 ), $summaries); 1298 1299 } 1300 1301 /** 1302 * @depends testValues 1303 */ 1304 function testOverridenEventNoValuesExpected() { 1305 1306 $vcal = new VCalendar(); 1307 $ev1 = $vcal->createComponent('VEVENT'); 1308 1309 $ev1->UID = 'overridden'; 1310 $ev1->RRULE = 'FREQ=WEEKLY;COUNT=3'; 1311 $ev1->DTSTART = '20120124T120000Z'; 1312 $ev1->SUMMARY = 'baseEvent'; 1313 1314 $vcal->add($ev1); 1315 1316 // ev2 overrides an event, and puts it 6 days earlier instead. 1317 $ev2 = $vcal->createComponent('VEVENT'); 1318 $ev2->UID = 'overridden'; 1319 $ev2->{'RECURRENCE-ID'} = '20120131T120000Z'; 1320 $ev2->DTSTART = '20120125T120000Z'; 1321 $ev2->SUMMARY = 'Override!'; 1322 1323 $vcal->add($ev2); 1324 1325 $it = new EventIterator($vcal,'overridden'); 1326 1327 $dates = array(); 1328 $summaries = array(); 1329 1330 // The reported problem was specifically related to the VCALENDAR 1331 // expansion. In this parcitular case, we had to forward to the 28th of 1332 // january. 1333 $it->fastForward(new DateTime('2012-01-28 23:00:00')); 1334 1335 // We stop the loop when it hits the 6th of februari. Normally this 1336 // iterator would hit 24, 25 (overriden from 31) and 7 feb but because 1337 // we 'filter' from the 28th till the 6th, we should get 0 results. 1338 while($it->valid() && $it->getDTSTart() < new DateTime('2012-02-06 23:00:00')) { 1339 1340 $dates[] = $it->getDTStart(); 1341 $summaries[] = (string)$it->getEventObject()->SUMMARY; 1342 $it->next(); 1343 1344 } 1345 1346 $this->assertEquals(array(), $dates); 1347 $this->assertEquals(array(), $summaries); 1348 1349 } 1350 1351 /** 1352 * @depends testValues 1353 */ 1354 function testRDATE() { 1355 1356 $vcal = new VCalendar(); 1357 $ev = $vcal->createComponent('VEVENT'); 1358 1359 $ev->UID = 'bla'; 1360 $ev->RDATE = array( 1361 new DateTime('2014-08-07', new DateTimeZone('UTC')), 1362 new DateTime('2014-08-08', new DateTimeZone('UTC')), 1363 ); 1364 $dtStart = $vcal->createProperty('DTSTART'); 1365 $dtStart->setDateTime(new DateTime('2011-10-07', new DateTimeZone('UTC'))); 1366 1367 $ev->add($dtStart); 1368 1369 $vcal->add($ev); 1370 1371 $it = new EventIterator($vcal,$ev->uid); 1372 1373 // Max is to prevent overflow 1374 $max = 12; 1375 $result = array(); 1376 foreach($it as $item) { 1377 1378 $result[] = $item; 1379 $max--; 1380 1381 if (!$max) break; 1382 1383 } 1384 1385 $tz = new DateTimeZone('UTC'); 1386 1387 $this->assertEquals( 1388 array( 1389 new DateTime('2011-10-07', $tz), 1390 new DateTime('2014-08-07', $tz), 1391 new DateTime('2014-08-08', $tz), 1392 ), 1393 $result 1394 ); 1395 1396 } 1397 1398 /** 1399 * @depends testValues 1400 * @expectedException \InvalidArgumentException 1401 */ 1402 function testNoMasterBadUID() { 1403 1404 $vcal = new VCalendar(); 1405 // ev2 overrides an event, and puts it on 2pm instead. 1406 $ev2 = $vcal->createComponent('VEVENT'); 1407 $ev2->UID = 'overridden'; 1408 $ev2->{'RECURRENCE-ID'} = '20120110T120000Z'; 1409 $ev2->DTSTART = '20120110T140000Z'; 1410 $ev2->SUMMARY = 'Event 2'; 1411 1412 $vcal->add($ev2); 1413 1414 // ev3 overrides an event, and puts it 2 days and 2 hours later 1415 $ev3 = $vcal->createComponent('VEVENT'); 1416 $ev3->UID = 'overridden'; 1417 $ev3->{'RECURRENCE-ID'} = '20120113T120000Z'; 1418 $ev3->DTSTART = '20120115T140000Z'; 1419 $ev3->SUMMARY = 'Event 3'; 1420 1421 $vcal->add($ev3); 1422 1423 $it = new EventIterator($vcal,'broken'); 1424 1425 } 1426} 1427 1428