1<?php 2 3namespace Sabre\VObject\Recur; 4 5use DateTime; 6use DateTimeZone; 7 8class RRuleIteratorTest extends \PHPUnit_Framework_TestCase { 9 10 function testHourly() { 11 12 $this->parse( 13 'FREQ=HOURLY;INTERVAL=3;COUNT=12', 14 '2011-10-07 12:00:00', 15 [ 16 '2011-10-07 12:00:00', 17 '2011-10-07 15:00:00', 18 '2011-10-07 18:00:00', 19 '2011-10-07 21:00:00', 20 '2011-10-08 00:00:00', 21 '2011-10-08 03:00:00', 22 '2011-10-08 06:00:00', 23 '2011-10-08 09:00:00', 24 '2011-10-08 12:00:00', 25 '2011-10-08 15:00:00', 26 '2011-10-08 18:00:00', 27 '2011-10-08 21:00:00', 28 ] 29 ); 30 31 } 32 33 function testDaily() { 34 35 $this->parse( 36 'FREQ=DAILY;INTERVAL=3;UNTIL=20111025T000000Z', 37 '2011-10-07', 38 [ 39 '2011-10-07 00:00:00', 40 '2011-10-10 00:00:00', 41 '2011-10-13 00:00:00', 42 '2011-10-16 00:00:00', 43 '2011-10-19 00:00:00', 44 '2011-10-22 00:00:00', 45 '2011-10-25 00:00:00', 46 ] 47 ); 48 49 } 50 51 function testDailyByDayByHour() { 52 53 $this->parse( 54 'FREQ=DAILY;BYDAY=SA,SU;BYHOUR=6,7', 55 '2011-10-08 06:00:00', 56 [ 57 '2011-10-08 06:00:00', 58 '2011-10-08 07:00:00', 59 '2011-10-09 06:00:00', 60 '2011-10-09 07:00:00', 61 '2011-10-15 06:00:00', 62 '2011-10-15 07:00:00', 63 '2011-10-16 06:00:00', 64 '2011-10-16 07:00:00', 65 '2011-10-22 06:00:00', 66 '2011-10-22 07:00:00', 67 '2011-10-23 06:00:00', 68 '2011-10-23 07:00:00', 69 ] 70 ); 71 72 } 73 74 function testDailyByHour() { 75 76 $this->parse( 77 'FREQ=DAILY;INTERVAL=2;BYHOUR=10,11,12,13,14,15', 78 '2012-10-11 12:00:00', 79 [ 80 '2012-10-11 12:00:00', 81 '2012-10-11 13:00:00', 82 '2012-10-11 14:00:00', 83 '2012-10-11 15:00:00', 84 '2012-10-13 10:00:00', 85 '2012-10-13 11:00:00', 86 '2012-10-13 12:00:00', 87 '2012-10-13 13:00:00', 88 '2012-10-13 14:00:00', 89 '2012-10-13 15:00:00', 90 '2012-10-15 10:00:00', 91 '2012-10-15 11:00:00', 92 ] 93 ); 94 95 } 96 97 function testDailyByDay() { 98 99 $this->parse( 100 'FREQ=DAILY;INTERVAL=2;BYDAY=TU,WE,FR', 101 '2011-10-07 12:00:00', 102 [ 103 '2011-10-07 12:00:00', 104 '2011-10-11 12:00:00', 105 '2011-10-19 12:00:00', 106 '2011-10-21 12:00:00', 107 '2011-10-25 12:00:00', 108 '2011-11-02 12:00:00', 109 '2011-11-04 12:00:00', 110 '2011-11-08 12:00:00', 111 '2011-11-16 12:00:00', 112 '2011-11-18 12:00:00', 113 '2011-11-22 12:00:00', 114 '2011-11-30 12:00:00', 115 ] 116 ); 117 118 } 119 120 function testDailyCount() { 121 122 $this->parse( 123 'FREQ=DAILY;COUNT=5', 124 '2014-08-01 18:03:00', 125 [ 126 '2014-08-01 18:03:00', 127 '2014-08-02 18:03:00', 128 '2014-08-03 18:03:00', 129 '2014-08-04 18:03:00', 130 '2014-08-05 18:03:00', 131 ] 132 ); 133 134 } 135 136 function testDailyByMonth() { 137 138 $this->parse( 139 'FREQ=DAILY;BYMONTH=9,10;BYDAY=SU', 140 '2007-10-04 16:00:00', 141 [ 142 '2013-09-29 16:00:00', 143 '2013-10-06 16:00:00', 144 '2013-10-13 16:00:00', 145 '2013-10-20 16:00:00', 146 '2013-10-27 16:00:00', 147 '2014-09-07 16:00:00' 148 ], 149 '2013-09-28' 150 ); 151 152 } 153 154 function testWeekly() { 155 156 $this->parse( 157 'FREQ=WEEKLY;INTERVAL=2;COUNT=10', 158 '2011-10-07 00:00:00', 159 [ 160 '2011-10-07 00:00:00', 161 '2011-10-21 00:00:00', 162 '2011-11-04 00:00:00', 163 '2011-11-18 00:00:00', 164 '2011-12-02 00:00:00', 165 '2011-12-16 00:00:00', 166 '2011-12-30 00:00:00', 167 '2012-01-13 00:00:00', 168 '2012-01-27 00:00:00', 169 '2012-02-10 00:00:00', 170 ] 171 ); 172 173 } 174 175 function testWeeklyByDay() { 176 177 $this->parse( 178 'FREQ=WEEKLY;INTERVAL=1;COUNT=4;BYDAY=MO;WKST=SA', 179 '2014-08-01 00:00:00', 180 [ 181 '2014-08-01 00:00:00', 182 '2014-08-04 00:00:00', 183 '2014-08-11 00:00:00', 184 '2014-08-18 00:00:00', 185 ] 186 ); 187 188 } 189 190 function testWeeklyByDay2() { 191 192 $this->parse( 193 'FREQ=WEEKLY;INTERVAL=2;BYDAY=TU,WE,FR;WKST=SU', 194 '2011-10-07 00:00:00', 195 [ 196 '2011-10-07 00:00:00', 197 '2011-10-18 00:00:00', 198 '2011-10-19 00:00:00', 199 '2011-10-21 00:00:00', 200 '2011-11-01 00:00:00', 201 '2011-11-02 00:00:00', 202 '2011-11-04 00:00:00', 203 '2011-11-15 00:00:00', 204 '2011-11-16 00:00:00', 205 '2011-11-18 00:00:00', 206 '2011-11-29 00:00:00', 207 '2011-11-30 00:00:00', 208 ] 209 ); 210 211 } 212 213 function testWeeklyByDayByHour() { 214 215 $this->parse( 216 'FREQ=WEEKLY;INTERVAL=2;BYDAY=TU,WE,FR;WKST=MO;BYHOUR=8,9,10', 217 '2011-10-07 08:00:00', 218 [ 219 '2011-10-07 08:00:00', 220 '2011-10-07 09:00:00', 221 '2011-10-07 10:00:00', 222 '2011-10-18 08:00:00', 223 '2011-10-18 09:00:00', 224 '2011-10-18 10:00:00', 225 '2011-10-19 08:00:00', 226 '2011-10-19 09:00:00', 227 '2011-10-19 10:00:00', 228 '2011-10-21 08:00:00', 229 '2011-10-21 09:00:00', 230 '2011-10-21 10:00:00', 231 '2011-11-01 08:00:00', 232 '2011-11-01 09:00:00', 233 '2011-11-01 10:00:00', 234 ] 235 ); 236 237 } 238 239 function testWeeklyByDaySpecificHour() { 240 241 $this->parse( 242 'FREQ=WEEKLY;INTERVAL=2;BYDAY=TU,WE,FR;WKST=SU', 243 '2011-10-07 18:00:00', 244 [ 245 '2011-10-07 18:00:00', 246 '2011-10-18 18:00:00', 247 '2011-10-19 18:00:00', 248 '2011-10-21 18:00:00', 249 '2011-11-01 18:00:00', 250 '2011-11-02 18:00:00', 251 '2011-11-04 18:00:00', 252 '2011-11-15 18:00:00', 253 '2011-11-16 18:00:00', 254 '2011-11-18 18:00:00', 255 '2011-11-29 18:00:00', 256 '2011-11-30 18:00:00', 257 ] 258 ); 259 260 } 261 262 function testMonthly() { 263 264 $this->parse( 265 'FREQ=MONTHLY;INTERVAL=3;COUNT=5', 266 '2011-12-05 00:00:00', 267 [ 268 '2011-12-05 00:00:00', 269 '2012-03-05 00:00:00', 270 '2012-06-05 00:00:00', 271 '2012-09-05 00:00:00', 272 '2012-12-05 00:00:00', 273 ] 274 ); 275 276 } 277 278 function testMonlthyEndOfMonth() { 279 280 $this->parse( 281 'FREQ=MONTHLY;INTERVAL=2;COUNT=12', 282 '2011-12-31 00:00:00', 283 [ 284 '2011-12-31 00:00:00', 285 '2012-08-31 00:00:00', 286 '2012-10-31 00:00:00', 287 '2012-12-31 00:00:00', 288 '2013-08-31 00:00:00', 289 '2013-10-31 00:00:00', 290 '2013-12-31 00:00:00', 291 '2014-08-31 00:00:00', 292 '2014-10-31 00:00:00', 293 '2014-12-31 00:00:00', 294 '2015-08-31 00:00:00', 295 '2015-10-31 00:00:00', 296 ] 297 ); 298 299 } 300 301 function testMonthlyByMonthDay() { 302 303 $this->parse( 304 'FREQ=MONTHLY;INTERVAL=5;COUNT=9;BYMONTHDAY=1,31,-7', 305 '2011-01-01 00:00:00', 306 [ 307 '2011-01-01 00:00:00', 308 '2011-01-25 00:00:00', 309 '2011-01-31 00:00:00', 310 '2011-06-01 00:00:00', 311 '2011-06-24 00:00:00', 312 '2011-11-01 00:00:00', 313 '2011-11-24 00:00:00', 314 '2012-04-01 00:00:00', 315 '2012-04-24 00:00:00', 316 ] 317 ); 318 319 } 320 321 function testMonthlyByDay() { 322 323 $this->parse( 324 'FREQ=MONTHLY;INTERVAL=2;COUNT=16;BYDAY=MO,-2TU,+1WE,3TH', 325 '2011-01-03 00:00:00', 326 [ 327 '2011-01-03 00:00:00', 328 '2011-01-05 00:00:00', 329 '2011-01-10 00:00:00', 330 '2011-01-17 00:00:00', 331 '2011-01-18 00:00:00', 332 '2011-01-20 00:00:00', 333 '2011-01-24 00:00:00', 334 '2011-01-31 00:00:00', 335 '2011-03-02 00:00:00', 336 '2011-03-07 00:00:00', 337 '2011-03-14 00:00:00', 338 '2011-03-17 00:00:00', 339 '2011-03-21 00:00:00', 340 '2011-03-22 00:00:00', 341 '2011-03-28 00:00:00', 342 '2011-05-02 00:00:00', 343 ] 344 ); 345 346 } 347 348 function testMonthlyByDayByMonthDay() { 349 350 $this->parse( 351 'FREQ=MONTHLY;COUNT=10;BYDAY=MO;BYMONTHDAY=1', 352 '2011-08-01 00:00:00', 353 [ 354 '2011-08-01 00:00:00', 355 '2012-10-01 00:00:00', 356 '2013-04-01 00:00:00', 357 '2013-07-01 00:00:00', 358 '2014-09-01 00:00:00', 359 '2014-12-01 00:00:00', 360 '2015-06-01 00:00:00', 361 '2016-02-01 00:00:00', 362 '2016-08-01 00:00:00', 363 '2017-05-01 00:00:00', 364 ] 365 ); 366 367 } 368 369 function testMonthlyByDayBySetPos() { 370 371 $this->parse( 372 'FREQ=MONTHLY;COUNT=10;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=1,-1', 373 '2011-01-03 00:00:00', 374 [ 375 '2011-01-03 00:00:00', 376 '2011-01-31 00:00:00', 377 '2011-02-01 00:00:00', 378 '2011-02-28 00:00:00', 379 '2011-03-01 00:00:00', 380 '2011-03-31 00:00:00', 381 '2011-04-01 00:00:00', 382 '2011-04-29 00:00:00', 383 '2011-05-02 00:00:00', 384 '2011-05-31 00:00:00', 385 ] 386 ); 387 388 } 389 390 function testYearly() { 391 392 $this->parse( 393 'FREQ=YEARLY;COUNT=10;INTERVAL=3', 394 '2011-01-01 00:00:00', 395 [ 396 '2011-01-01 00:00:00', 397 '2014-01-01 00:00:00', 398 '2017-01-01 00:00:00', 399 '2020-01-01 00:00:00', 400 '2023-01-01 00:00:00', 401 '2026-01-01 00:00:00', 402 '2029-01-01 00:00:00', 403 '2032-01-01 00:00:00', 404 '2035-01-01 00:00:00', 405 '2038-01-01 00:00:00', 406 ] 407 ); 408 } 409 410 function testYearlyLeapYear() { 411 412 $this->parse( 413 'FREQ=YEARLY;COUNT=3', 414 '2012-02-29 00:00:00', 415 [ 416 '2012-02-29 00:00:00', 417 '2016-02-29 00:00:00', 418 '2020-02-29 00:00:00', 419 ] 420 ); 421 } 422 423 function testYearlyByMonth() { 424 425 $this->parse( 426 'FREQ=YEARLY;COUNT=8;INTERVAL=4;BYMONTH=4,10', 427 '2011-04-07 00:00:00', 428 [ 429 '2011-04-07 00:00:00', 430 '2011-10-07 00:00:00', 431 '2015-04-07 00:00:00', 432 '2015-10-07 00:00:00', 433 '2019-04-07 00:00:00', 434 '2019-10-07 00:00:00', 435 '2023-04-07 00:00:00', 436 '2023-10-07 00:00:00', 437 ] 438 ); 439 440 } 441 442 /** 443 * @expectedException \Sabre\VObject\InvalidDataException 444 */ 445 function testYearlyByMonthInvalidValue1() { 446 447 $this->parse( 448 'FREQ=YEARLY;COUNT=6;BYMONTHDAY=24;BYMONTH=0', 449 '2011-04-07 00:00:00', 450 [] 451 ); 452 453 } 454 455 /** 456 * @expectedException \Sabre\VObject\InvalidDataException 457 */ 458 function testYearlyByMonthInvalidValue2() { 459 460 $this->parse( 461 'FREQ=YEARLY;COUNT=6;BYMONTHDAY=24;BYMONTH=bla', 462 '2011-04-07 00:00:00', 463 [] 464 ); 465 466 } 467 468 /** 469 * @expectedException \Sabre\VObject\InvalidDataException 470 */ 471 function testYearlyByMonthManyInvalidValues() { 472 473 $this->parse( 474 'FREQ=YEARLY;COUNT=6;BYMONTHDAY=24;BYMONTH=0,bla', 475 '2011-04-07 00:00:00', 476 [] 477 ); 478 479 } 480 481 /** 482 * @expectedException \Sabre\VObject\InvalidDataException 483 */ 484 function testYearlyByMonthEmptyValue() { 485 486 $this->parse( 487 'FREQ=YEARLY;COUNT=6;BYMONTHDAY=24;BYMONTH=', 488 '2011-04-07 00:00:00', 489 [] 490 ); 491 492 } 493 494 function testYearlyByMonthByDay() { 495 496 $this->parse( 497 'FREQ=YEARLY;COUNT=8;INTERVAL=5;BYMONTH=4,10;BYDAY=1MO,-1SU', 498 '2011-04-04 00:00:00', 499 [ 500 '2011-04-04 00:00:00', 501 '2011-04-24 00:00:00', 502 '2011-10-03 00:00:00', 503 '2011-10-30 00:00:00', 504 '2016-04-04 00:00:00', 505 '2016-04-24 00:00:00', 506 '2016-10-03 00:00:00', 507 '2016-10-30 00:00:00', 508 ] 509 ); 510 511 } 512 513 function testYearlyByYearDay() { 514 515 $this->parse( 516 'FREQ=YEARLY;COUNT=7;INTERVAL=2;BYYEARDAY=190', 517 '2011-07-10 03:07:00', 518 [ 519 '2011-07-10 03:07:00', 520 '2013-07-10 03:07:00', 521 '2015-07-10 03:07:00', 522 '2017-07-10 03:07:00', 523 '2019-07-10 03:07:00', 524 '2021-07-10 03:07:00', 525 '2023-07-10 03:07:00', 526 ] 527 ); 528 529 } 530 531 function testYearlyByYearDayMultiple() { 532 533 $this->parse( 534 'FREQ=YEARLY;COUNT=8;INTERVAL=3;BYYEARDAY=190,301', 535 '2011-07-10 14:53:11', 536 [ 537 '2011-07-10 14:53:11', 538 '2011-10-29 14:53:11', 539 '2014-07-10 14:53:11', 540 '2014-10-29 14:53:11', 541 '2017-07-10 14:53:11', 542 '2017-10-29 14:53:11', 543 '2020-07-09 14:53:11', 544 '2020-10-28 14:53:11', 545 ] 546 ); 547 548 } 549 550 function testYearlyByYearDayByDay() { 551 552 $this->parse( 553 'FREQ=YEARLY;COUNT=6;BYYEARDAY=97;BYDAY=SA', 554 '2001-04-07 14:53:11', 555 [ 556 '2001-04-07 14:53:11', 557 '2006-04-08 14:53:11', 558 '2012-04-07 14:53:11', 559 '2017-04-08 14:53:11', 560 '2023-04-08 14:53:11', 561 '2034-04-08 14:53:11', 562 ] 563 ); 564 565 } 566 567 function testYearlyByYearDayNegative() { 568 569 $this->parse( 570 'FREQ=YEARLY;COUNT=8;BYYEARDAY=-97,-5', 571 '2001-09-26 14:53:11', 572 [ 573 '2001-09-26 14:53:11', 574 '2001-12-27 14:53:11', 575 '2002-09-26 14:53:11', 576 '2002-12-27 14:53:11', 577 '2003-09-26 14:53:11', 578 '2003-12-27 14:53:11', 579 '2004-09-26 14:53:11', 580 '2004-12-27 14:53:11', 581 ] 582 ); 583 584 } 585 586 /** 587 * @expectedException \Sabre\VObject\InvalidDataException 588 */ 589 function testYearlyByYearDayInvalid390() { 590 591 $this->parse( 592 'FREQ=YEARLY;COUNT=8;INTERVAL=4;BYYEARDAY=390', 593 '2011-04-07 00:00:00', 594 [ 595 ] 596 ); 597 598 } 599 600 /** 601 * @expectedException \Sabre\VObject\InvalidDataException 602 */ 603 function testYearlyByYearDayInvalid0() { 604 605 $this->parse( 606 'FREQ=YEARLY;COUNT=8;INTERVAL=4;BYYEARDAY=0', 607 '2011-04-07 00:00:00', 608 [ 609 ] 610 ); 611 612 } 613 614 function testFastForward() { 615 616 // The idea is that we're fast-forwarding too far in the future, so 617 // there will be no results left. 618 $this->parse( 619 'FREQ=YEARLY;COUNT=8;INTERVAL=5;BYMONTH=4,10;BYDAY=1MO,-1SU', 620 '2011-04-04 00:00:00', 621 [], 622 '2020-05-05 00:00:00' 623 ); 624 625 } 626 627 /** 628 * The bug that was in the 629 * system before would fail on the 5th tuesday of the month, if the 5th 630 * tuesday did not exist. 631 * 632 * A pretty slow test. Had to be marked as 'medium' for phpunit to not die 633 * after 1 second. Would be good to optimize later. 634 * 635 * @medium 636 */ 637 function testFifthTuesdayProblem() { 638 639 $this->parse( 640 'FREQ=MONTHLY;INTERVAL=1;UNTIL=20071030T035959Z;BYDAY=5TU', 641 '2007-10-04 14:46:42', 642 [ 643 '2007-10-04 14:46:42', 644 ] 645 ); 646 647 } 648 649 /** 650 * This bug came from a Fruux customer. This would result in a never-ending 651 * request. 652 */ 653 function testFastFowardTooFar() { 654 655 $this->parse( 656 'FREQ=WEEKLY;BYDAY=MO;UNTIL=20090704T205959Z;INTERVAL=1', 657 '2009-04-20 18:00:00', 658 [ 659 '2009-04-20 18:00:00', 660 '2009-04-27 18:00:00', 661 '2009-05-04 18:00:00', 662 '2009-05-11 18:00:00', 663 '2009-05-18 18:00:00', 664 '2009-05-25 18:00:00', 665 '2009-06-01 18:00:00', 666 '2009-06-08 18:00:00', 667 '2009-06-15 18:00:00', 668 '2009-06-22 18:00:00', 669 '2009-06-29 18:00:00', 670 ] 671 ); 672 673 } 674 675 function testValidByWeekNo() { 676 677 $this->parse( 678 'FREQ=YEARLY;BYWEEKNO=20;BYDAY=TU', 679 '2011-02-07 00:00:00', 680 [ 681 '2011-02-07 00:00:00', 682 '2011-05-17 00:00:00', 683 '2012-05-15 00:00:00', 684 '2013-05-14 00:00:00', 685 '2014-05-13 00:00:00', 686 '2015-05-12 00:00:00', 687 '2016-05-17 00:00:00', 688 '2017-05-16 00:00:00', 689 '2018-05-15 00:00:00', 690 '2019-05-14 00:00:00', 691 '2020-05-12 00:00:00', 692 '2021-05-18 00:00:00', 693 ] 694 ); 695 696 } 697 698 function testNegativeValidByWeekNo() { 699 700 $this->parse( 701 'FREQ=YEARLY;BYWEEKNO=-20;BYDAY=TU,FR', 702 '2011-09-02 00:00:00', 703 [ 704 '2011-09-02 00:00:00', 705 '2012-08-07 00:00:00', 706 '2012-08-10 00:00:00', 707 '2013-08-06 00:00:00', 708 '2013-08-09 00:00:00', 709 '2014-08-05 00:00:00', 710 '2014-08-08 00:00:00', 711 '2015-08-11 00:00:00', 712 '2015-08-14 00:00:00', 713 '2016-08-09 00:00:00', 714 '2016-08-12 00:00:00', 715 '2017-08-08 00:00:00', 716 ] 717 ); 718 719 } 720 721 function testTwoValidByWeekNo() { 722 723 $this->parse( 724 'FREQ=YEARLY;BYWEEKNO=20;BYDAY=TU,FR', 725 '2011-09-07 09:00:00', 726 [ 727 '2011-09-07 09:00:00', 728 '2012-05-15 09:00:00', 729 '2012-05-18 09:00:00', 730 '2013-05-14 09:00:00', 731 '2013-05-17 09:00:00', 732 '2014-05-13 09:00:00', 733 '2014-05-16 09:00:00', 734 '2015-05-12 09:00:00', 735 '2015-05-15 09:00:00', 736 '2016-05-17 09:00:00', 737 '2016-05-20 09:00:00', 738 '2017-05-16 09:00:00', 739 ] 740 ); 741 742 } 743 744 function testValidByWeekNoByDayDefault() { 745 746 $this->parse( 747 'FREQ=YEARLY;BYWEEKNO=20', 748 '2011-05-16 00:00:00', 749 [ 750 '2011-05-16 00:00:00', 751 '2012-05-14 00:00:00', 752 '2013-05-13 00:00:00', 753 '2014-05-12 00:00:00', 754 '2015-05-11 00:00:00', 755 '2016-05-16 00:00:00', 756 '2017-05-15 00:00:00', 757 '2018-05-14 00:00:00', 758 '2019-05-13 00:00:00', 759 '2020-05-11 00:00:00', 760 '2021-05-17 00:00:00', 761 '2022-05-16 00:00:00', 762 ] 763 ); 764 765 } 766 767 function testMultipleValidByWeekNo() { 768 769 $this->parse( 770 'FREQ=YEARLY;BYWEEKNO=20,50;BYDAY=TU,FR', 771 '2011-01-16 00:00:00', 772 [ 773 '2011-01-16 00:00:00', 774 '2011-05-17 00:00:00', 775 '2011-05-20 00:00:00', 776 '2011-12-13 00:00:00', 777 '2011-12-16 00:00:00', 778 '2012-05-15 00:00:00', 779 '2012-05-18 00:00:00', 780 '2012-12-11 00:00:00', 781 '2012-12-14 00:00:00', 782 '2013-05-14 00:00:00', 783 '2013-05-17 00:00:00', 784 '2013-12-10 00:00:00', 785 ] 786 ); 787 788 } 789 790 /** 791 * @expectedException \Sabre\VObject\InvalidDataException 792 */ 793 function testInvalidByWeekNo() { 794 795 $this->parse( 796 'FREQ=YEARLY;BYWEEKNO=54', 797 '2011-05-16 00:00:00', 798 [ 799 ] 800 ); 801 802 } 803 804 /** 805 * This also at one point caused an infinite loop. We're keeping the test. 806 */ 807 function testYearlyByMonthLoop() { 808 809 $this->parse( 810 'FREQ=YEARLY;INTERVAL=1;UNTIL=20120203T225959Z;BYMONTH=2;BYSETPOS=1;BYDAY=SU,MO,TU,WE,TH,FR,SA', 811 '2012-01-01 15:45:00', 812 [ 813 '2012-02-01 15:45:00', 814 ], 815 '2012-01-29 23:00:00' 816 ); 817 818 819 } 820 821 /** 822 * Something, somewhere produced an ics with an interval set to 0. Because 823 * this means we increase the current day (or week, month) by 0, this also 824 * results in an infinite loop. 825 * 826 * @expectedException \Sabre\VObject\InvalidDataException 827 */ 828 function testZeroInterval() { 829 830 $this->parse( 831 'FREQ=YEARLY;INTERVAL=0', 832 '2012-08-24 14:57:00', 833 [], 834 '2013-01-01 23:00:00' 835 ); 836 837 } 838 839 /** 840 * @expectedException \Sabre\VObject\InvalidDataException 841 */ 842 function testInvalidFreq() { 843 844 $this->parse( 845 'FREQ=SMONTHLY;INTERVAL=3;UNTIL=20111025T000000Z', 846 '2011-10-07', 847 [] 848 ); 849 850 } 851 852 /** 853 * @expectedException \Sabre\VObject\InvalidDataException 854 */ 855 function testByDayBadOffset() { 856 857 $this->parse( 858 'FREQ=WEEKLY;INTERVAL=1;COUNT=4;BYDAY=0MO;WKST=SA', 859 '2014-08-01 00:00:00', 860 [] 861 ); 862 863 } 864 865 function testUntilBeginHasTimezone() { 866 867 $this->parse( 868 'FREQ=WEEKLY;UNTIL=20131118T183000', 869 '2013-09-23 18:30:00', 870 [ 871 '2013-09-23 18:30:00', 872 '2013-09-30 18:30:00', 873 '2013-10-07 18:30:00', 874 '2013-10-14 18:30:00', 875 '2013-10-21 18:30:00', 876 '2013-10-28 18:30:00', 877 '2013-11-04 18:30:00', 878 '2013-11-11 18:30:00', 879 '2013-11-18 18:30:00', 880 ], 881 null, 882 'America/New_York' 883 ); 884 885 } 886 887 function testUntilBeforeDtStart() { 888 889 $this->parse( 890 'FREQ=DAILY;UNTIL=20140101T000000Z', 891 '2014-08-02 00:15:00', 892 [ 893 '2014-08-02 00:15:00', 894 ] 895 ); 896 897 } 898 899 function testIgnoredStuff() { 900 901 $this->parse( 902 'FREQ=DAILY;BYSECOND=1;BYMINUTE=1;BYYEARDAY=1;BYWEEKNO=1;COUNT=2', 903 '2014-08-02 00:15:00', 904 [ 905 '2014-08-02 00:15:00', 906 '2014-08-03 00:15:00', 907 ] 908 ); 909 910 } 911 912 function testMinusFifthThursday() { 913 914 $this->parse( 915 'FREQ=MONTHLY;BYDAY=-4TH,-5TH;COUNT=4', 916 '2015-01-01 00:15:00', 917 [ 918 '2015-01-01 00:15:00', 919 '2015-01-08 00:15:00', 920 '2015-02-05 00:15:00', 921 '2015-03-05 00:15:00' 922 ] 923 ); 924 925 } 926 927 /** 928 * @expectedException \Sabre\VObject\InvalidDataException 929 */ 930 function testUnsupportedPart() { 931 932 $this->parse( 933 'FREQ=DAILY;BYWODAN=1', 934 '2014-08-02 00:15:00', 935 [] 936 ); 937 938 } 939 940 function testIteratorFunctions() { 941 942 $parser = new RRuleIterator('FREQ=DAILY', new DateTime('2014-08-02 00:00:13')); 943 $parser->next(); 944 $this->assertEquals( 945 new DateTime('2014-08-03 00:00:13'), 946 $parser->current() 947 ); 948 $this->assertEquals( 949 1, 950 $parser->key() 951 ); 952 953 $parser->rewind(); 954 955 $this->assertEquals( 956 new DateTime('2014-08-02 00:00:13'), 957 $parser->current() 958 ); 959 $this->assertEquals( 960 0, 961 $parser->key() 962 ); 963 964 } 965 966 function parse($rule, $start, $expected, $fastForward = null, $tz = 'UTC') { 967 968 $dt = new DateTime($start, new DateTimeZone($tz)); 969 $parser = new RRuleIterator($rule, $dt); 970 971 if ($fastForward) { 972 $parser->fastForward(new DateTime($fastForward)); 973 } 974 975 $result = []; 976 while ($parser->valid()) { 977 978 $item = $parser->current(); 979 $result[] = $item->format('Y-m-d H:i:s'); 980 981 if ($parser->isInfinite() && count($result) >= count($expected)) { 982 break; 983 } 984 $parser->next(); 985 986 } 987 988 $this->assertEquals( 989 $expected, 990 $result 991 ); 992 993 } 994 995} 996