1<?php 2 3namespace Sabre\VObject; 4 5class FreeBusyGeneratorTest extends \PHPUnit_Framework_TestCase { 6 7 use PHPUnitAssertions; 8 9 function testGeneratorBaseObject() { 10 11 $obj = new Component\VCalendar(); 12 $obj->METHOD = 'PUBLISH'; 13 14 $gen = new FreeBusyGenerator(); 15 $gen->setObjects([]); 16 $gen->setBaseObject($obj); 17 18 $result = $gen->getResult(); 19 20 $this->assertEquals('PUBLISH', $result->METHOD->getValue()); 21 22 } 23 24 /** 25 * @expectedException InvalidArgumentException 26 */ 27 function testInvalidArg() { 28 29 $gen = new FreeBusyGenerator( 30 new \DateTime('2012-01-01'), 31 new \DateTime('2012-12-31'), 32 new \StdClass() 33 ); 34 35 } 36 37 /** 38 * This function takes a list of objects (icalendar objects), and turns 39 * them into a freebusy report. 40 * 41 * Then it takes the expected output and compares it to what we actually 42 * got. 43 * 44 * It only generates the freebusy report for the following time-range: 45 * 2011-01-01 11:00:00 until 2011-01-03 11:11:11 46 * 47 * @param string $expected 48 * @param array $input 49 * @param string|null $timeZone 50 * @param string $vavailability 51 * @return void 52 */ 53 function assertFreeBusyReport($expected, $input, $timeZone = null, $vavailability = null) { 54 55 $gen = new FreeBusyGenerator( 56 new \DateTime('20110101T110000Z', new \DateTimeZone('UTC')), 57 new \DateTime('20110103T110000Z', new \DateTimeZone('UTC')), 58 $input, 59 $timeZone 60 ); 61 62 if ($vavailability) { 63 if (is_string($vavailability)) { 64 $vavailability = Reader::read($vavailability); 65 } 66 $gen->setVAvailability($vavailability); 67 } 68 69 $output = $gen->getResult(); 70 71 // Removing DTSTAMP because it changes every time. 72 unset($output->VFREEBUSY->DTSTAMP); 73 74 $expected = <<<ICS 75BEGIN:VCALENDAR 76VERSION:2.0 77BEGIN:VFREEBUSY 78DTSTART:20110101T110000Z 79DTEND:20110103T110000Z 80$expected 81END:VFREEBUSY 82END:VCALENDAR 83ICS; 84 85 $this->assertVObjectEqualsVObject($expected, $output); 86 87 } 88 89 function testSimple() { 90 91 $blob = <<<ICS 92BEGIN:VCALENDAR 93BEGIN:VEVENT 94UID:foobar 95DTSTART:20110101T120000Z 96DTEND:20110101T130000Z 97END:VEVENT 98END:VCALENDAR 99ICS; 100 101 102 $this->assertFreeBusyReport( 103 "FREEBUSY:20110101T120000Z/20110101T130000Z", 104 $blob 105 ); 106 107 } 108 109 function testSource() { 110 111 $blob = <<<ICS 112BEGIN:VCALENDAR 113BEGIN:VEVENT 114UID:foobar 115DTSTART:20110101T120000Z 116DTEND:20110101T130000Z 117END:VEVENT 118END:VCALENDAR 119ICS; 120 $h = fopen('php://memory', 'r+'); 121 fwrite($h, $blob); 122 rewind($h); 123 124 125 $this->assertFreeBusyReport( 126 "FREEBUSY:20110101T120000Z/20110101T130000Z", 127 $h 128 ); 129 130 } 131 132 /** 133 * Testing TRANSP:OPAQUE 134 */ 135 function testOpaque() { 136 137 $blob = <<<ICS 138BEGIN:VCALENDAR 139BEGIN:VEVENT 140UID:foobar2 141TRANSP:OPAQUE 142DTSTART:20110101T130000Z 143DTEND:20110101T140000Z 144END:VEVENT 145END:VCALENDAR 146ICS; 147 148 $this->assertFreeBusyReport( 149 "FREEBUSY:20110101T130000Z/20110101T140000Z", 150 $blob 151 ); 152 153 } 154 155 /** 156 * Testing TRANSP:TRANSPARENT 157 */ 158 function testTransparent() { 159 160 // transparent, hidden 161 $blob = <<<ICS 162BEGIN:VCALENDAR 163BEGIN:VEVENT 164UID:foobar3 165TRANSP:TRANSPARENT 166DTSTART:20110101T140000Z 167DTEND:20110101T150000Z 168END:VEVENT 169END:VCALENDAR 170ICS; 171 172 $this->assertFreeBusyReport( 173 "", 174 $blob 175 ); 176 177 } 178 179 /** 180 * Testing STATUS:CANCELLED 181 */ 182 function testCancelled() { 183 184 // transparent, hidden 185 $blob = <<<ICS 186BEGIN:VCALENDAR 187BEGIN:VEVENT 188UID:foobar4 189STATUS:CANCELLED 190DTSTART:20110101T160000Z 191DTEND:20110101T170000Z 192END:VEVENT 193END:VCALENDAR 194ICS; 195 196 $this->assertFreeBusyReport( 197 "", 198 $blob 199 ); 200 201 } 202 203 /** 204 * Testing STATUS:TENTATIVE 205 */ 206 function testTentative() { 207 208 // tentative, shows up 209 $blob = <<<ICS 210BEGIN:VCALENDAR 211BEGIN:VEVENT 212UID:foobar5 213STATUS:TENTATIVE 214DTSTART:20110101T180000Z 215DTEND:20110101T190000Z 216END:VEVENT 217END:VCALENDAR 218ICS; 219 220 $this->assertFreeBusyReport( 221 'FREEBUSY;FBTYPE=BUSY-TENTATIVE:20110101T180000Z/20110101T190000Z', 222 $blob 223 ); 224 225 } 226 227 /** 228 * Testing an event that falls outside of the report time-range. 229 */ 230 function testOutsideTimeRange() { 231 232 // outside of time-range, hidden 233 $blob = <<<ICS 234BEGIN:VCALENDAR 235BEGIN:VEVENT 236UID:foobar6 237DTSTART:20110101T090000Z 238DTEND:20110101T100000Z 239END:VEVENT 240END:VCALENDAR 241ICS; 242 243 $this->assertFreeBusyReport( 244 '', 245 $blob 246 ); 247 248 } 249 250 /** 251 * Testing an event that falls outside of the report time-range. 252 */ 253 function testOutsideTimeRange2() { 254 255 // outside of time-range, hidden 256 $blob = <<<ICS 257BEGIN:VCALENDAR 258BEGIN:VEVENT 259UID:foobar7 260DTSTART:20110104T090000Z 261DTEND:20110104T100000Z 262END:VEVENT 263END:VCALENDAR 264ICS; 265 266 $this->assertFreeBusyReport( 267 '', 268 $blob 269 ); 270 271 } 272 273 /** 274 * Testing an event that uses DURATION 275 */ 276 function testDuration() { 277 278 // using duration, shows up 279 $blob = <<<ICS 280BEGIN:VCALENDAR 281BEGIN:VEVENT 282UID:foobar8 283DTSTART:20110101T190000Z 284DURATION:PT1H 285END:VEVENT 286END:VCALENDAR 287ICS; 288 289 $this->assertFreeBusyReport( 290 'FREEBUSY:20110101T190000Z/20110101T200000Z', 291 $blob 292 ); 293 294 } 295 296 /** 297 * Testing an all-day event 298 */ 299 function testAllDay() { 300 301 // Day-long event, shows up 302 $blob = <<<ICS 303BEGIN:VCALENDAR 304BEGIN:VEVENT 305UID:foobar9 306DTSTART;VALUE=DATE:20110102 307END:VEVENT 308END:VCALENDAR 309ICS; 310 311 $this->assertFreeBusyReport( 312 'FREEBUSY:20110102T000000Z/20110103T000000Z', 313 $blob 314 ); 315 316 } 317 318 /** 319 * Testing an event that has no end or duration. 320 */ 321 function testNoDuration() { 322 323 // No duration, does not show up 324 $blob = <<<ICS 325BEGIN:VCALENDAR 326BEGIN:VEVENT 327UID:foobar10 328DTSTART:20110101T200000Z 329END:VEVENT 330END:VCALENDAR 331ICS; 332 333 $this->assertFreeBusyReport( 334 '', 335 $blob 336 ); 337 338 } 339 340 /** 341 * Testing feeding the freebusy generator an object instead of a string. 342 */ 343 function testObject() { 344 345 // encoded as object, shows up 346 $blob = <<<ICS 347BEGIN:VCALENDAR 348BEGIN:VEVENT 349UID:foobar11 350DTSTART:20110101T210000Z 351DURATION:PT1H 352END:VEVENT 353END:VCALENDAR 354ICS; 355 356 $this->assertFreeBusyReport( 357 'FREEBUSY:20110101T210000Z/20110101T220000Z', 358 Reader::read($blob) 359 ); 360 361 362 } 363 364 /** 365 * Testing feeding VFREEBUSY objects instead of VEVENT 366 */ 367 function testVFreeBusy() { 368 369 // Freebusy. Some parts show up 370 $blob = <<<ICS 371BEGIN:VCALENDAR 372BEGIN:VFREEBUSY 373FREEBUSY:20110103T010000Z/20110103T020000Z 374FREEBUSY;FBTYPE=FREE:20110103T020000Z/20110103T030000Z 375FREEBUSY:20110103T030000Z/20110103T040000Z,20110103T040000Z/20110103T050000Z 376FREEBUSY:20120101T000000Z/20120101T010000Z 377FREEBUSY:20110103T050000Z/PT1H 378END:VFREEBUSY 379END:VCALENDAR 380ICS; 381 382 $this->assertFreeBusyReport( 383 "FREEBUSY:20110103T010000Z/20110103T020000Z\n" . 384 'FREEBUSY:20110103T030000Z/20110103T060000Z', 385 $blob 386 ); 387 388 } 389 390 function testYearlyRecurrence() { 391 392 // Yearly recurrence rule, shows up 393 $blob = <<<ICS 394BEGIN:VCALENDAR 395BEGIN:VEVENT 396UID:foobar13 397DTSTART:20100101T220000Z 398DTEND:20100101T230000Z 399RRULE:FREQ=YEARLY 400END:VEVENT 401END:VCALENDAR 402ICS; 403 404 $this->assertFreeBusyReport( 405 'FREEBUSY:20110101T220000Z/20110101T230000Z', 406 $blob 407 ); 408 409 } 410 411 function testYearlyRecurrenceDuration() { 412 413 // Yearly recurrence rule + duration, shows up 414 $blob = <<<ICS 415BEGIN:VCALENDAR 416BEGIN:VEVENT 417UID:foobar14 418DTSTART:20100101T230000Z 419DURATION:PT1H 420RRULE:FREQ=YEARLY 421END:VEVENT 422END:VCALENDAR 423ICS; 424 425 $this->assertFreeBusyReport( 426 'FREEBUSY:20110101T230000Z/20110102T000000Z', 427 $blob 428 ); 429 430 } 431 432 function testFloatingTime() { 433 434 // Floating time, no timezone 435 $blob = <<<ICS 436BEGIN:VCALENDAR 437BEGIN:VEVENT 438UID:foobar 439DTSTART:20110101T120000 440DTEND:20110101T130000 441END:VEVENT 442END:VCALENDAR 443ICS; 444 445 $this->assertFreeBusyReport( 446 "FREEBUSY:20110101T120000Z/20110101T130000Z", 447 $blob 448 ); 449 450 } 451 452 function testFloatingTimeReferenceTimeZone() { 453 454 // Floating time + reference timezone 455 $blob = <<<ICS 456BEGIN:VCALENDAR 457BEGIN:VEVENT 458UID:foobar 459DTSTART:20110101T120000 460DTEND:20110101T130000 461END:VEVENT 462END:VCALENDAR 463ICS; 464 465 $this->assertFreeBusyReport( 466 "FREEBUSY:20110101T170000Z/20110101T180000Z", 467 $blob, 468 new \DateTimeZone('America/Toronto') 469 ); 470 471 } 472 473 function testAllDay2() { 474 475 // All-day event, slightly outside of the VFREEBUSY range. 476 $blob = <<<ICS 477BEGIN:VCALENDAR 478BEGIN:VEVENT 479UID:foobar 480DTSTART;VALUE=DATE:20110101 481END:VEVENT 482END:VCALENDAR 483ICS; 484 485 $this->assertFreeBusyReport( 486 "FREEBUSY:20110101T110000Z/20110102T000000Z", 487 $blob 488 ); 489 490 } 491 492 function testAllDayReferenceTimeZone() { 493 494 // All-day event + reference timezone 495 $blob = <<<ICS 496BEGIN:VCALENDAR 497BEGIN:VEVENT 498UID:foobar 499DTSTART;VALUE=DATE:20110101 500END:VEVENT 501END:VCALENDAR 502ICS; 503 504 $this->assertFreeBusyReport( 505 "FREEBUSY:20110101T110000Z/20110102T050000Z", 506 $blob, 507 new \DateTimeZone('America/Toronto') 508 ); 509 510 } 511 512 function testNoValidInstances() { 513 514 // Recurrence rule with no valid instances 515 $blob = <<<ICS 516BEGIN:VCALENDAR 517BEGIN:VEVENT 518UID:foobar 519DTSTART:20110101T100000Z 520DTEND:20110103T120000Z 521RRULE:FREQ=WEEKLY;COUNT=1 522EXDATE:20110101T100000Z 523END:VEVENT 524END:VCALENDAR 525ICS; 526 527 $this->assertFreeBusyReport( 528 "", 529 $blob 530 ); 531 532 } 533 534 /** 535 * This VAVAILABILITY object overlaps with the time-range, but we're just 536 * busy the entire time. 537 */ 538 function testVAvailabilitySimple() { 539 540 $blob = <<<ICS 541BEGIN:VCALENDAR 542BEGIN:VEVENT 543UID:lalala 544DTSTART:20110101T120000Z 545DTEND:20110101T130000Z 546END:VEVENT 547END:VCALENDAR 548ICS; 549 550 $vavail = <<<ICS 551BEGIN:VCALENDAR 552BEGIN:VAVAILABILITY 553DTSTART:20110101T000000Z 554DTEND:20120101T000000Z 555BEGIN:AVAILABLE 556DTSTART:20110101T000000Z 557DTEND:20110101T010000Z 558END:AVAILABLE 559END:VAVAILABILITY 560END:VCALENDAR 561ICS; 562 563 $this->assertFreeBusyReport( 564 "FREEBUSY;FBTYPE=BUSY-UNAVAILABLE:20110101T110000Z/20110101T120000Z\n" . 565 "FREEBUSY:20110101T120000Z/20110101T130000Z\n" . 566 "FREEBUSY;FBTYPE=BUSY-UNAVAILABLE:20110101T130000Z/20110103T110000Z", 567 $blob, 568 null, 569 $vavail 570 ); 571 572 } 573 574 /** 575 * This VAVAILABILITY object does not overlap at all with the freebusy 576 * report, so it should be ignored. 577 */ 578 function testVAvailabilityIrrelevant() { 579 580 $blob = <<<ICS 581BEGIN:VCALENDAR 582BEGIN:VEVENT 583UID:lalala 584DTSTART:20110101T120000Z 585DTEND:20110101T130000Z 586END:VEVENT 587END:VCALENDAR 588ICS; 589 590 $vavail = <<<ICS 591BEGIN:VCALENDAR 592BEGIN:VAVAILABILITY 593DTSTART:20150101T000000Z 594DTEND:20160101T000000Z 595BEGIN:AVAILABLE 596DTSTART:20150101T000000Z 597DTEND:20150101T010000Z 598END:AVAILABLE 599END:VAVAILABILITY 600END:VCALENDAR 601ICS; 602 603 $this->assertFreeBusyReport( 604 "FREEBUSY:20110101T120000Z/20110101T130000Z", 605 $blob, 606 null, 607 $vavail 608 ); 609 610 } 611 612 /** 613 * This VAVAILABILITY object has a 9am-5pm AVAILABLE object for office 614 * hours. 615 */ 616 function testVAvailabilityOfficeHours() { 617 618 $blob = <<<ICS 619BEGIN:VCALENDAR 620BEGIN:VEVENT 621UID:lalala 622DTSTART:20110101T120000Z 623DTEND:20110101T130000Z 624END:VEVENT 625END:VCALENDAR 626ICS; 627 628 $vavail = <<<ICS 629BEGIN:VCALENDAR 630BEGIN:VAVAILABILITY 631DTSTART:20100101T000000Z 632DTEND:20120101T000000Z 633BUSYTYPE:BUSY-TENTATIVE 634BEGIN:AVAILABLE 635DTSTART:20101213T090000Z 636DTEND:20101213T170000Z 637RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR 638END:AVAILABLE 639END:VAVAILABILITY 640END:VCALENDAR 641ICS; 642 643 $this->assertFreeBusyReport( 644 "FREEBUSY;FBTYPE=BUSY-TENTATIVE:20110101T110000Z/20110101T120000Z\n" . 645 "FREEBUSY:20110101T120000Z/20110101T130000Z\n" . 646 "FREEBUSY;FBTYPE=BUSY-TENTATIVE:20110101T130000Z/20110103T090000Z\n", 647 $blob, 648 null, 649 $vavail 650 ); 651 652 } 653 654 /** 655 * This test has the same office hours, but has a vacation blocked off for 656 * the relevant time, using a higher priority. (lower number). 657 */ 658 function testVAvailabilityOfficeHoursVacation() { 659 660 $blob = <<<ICS 661BEGIN:VCALENDAR 662BEGIN:VEVENT 663UID:lalala 664DTSTART:20110101T120000Z 665DTEND:20110101T130000Z 666END:VEVENT 667END:VCALENDAR 668ICS; 669 670 $vavail = <<<ICS 671BEGIN:VCALENDAR 672BEGIN:VAVAILABILITY 673DTSTART:20100101T000000Z 674DTEND:20120101T000000Z 675BUSYTYPE:BUSY-TENTATIVE 676PRIORITY:2 677BEGIN:AVAILABLE 678DTSTART:20101213T090000Z 679DTEND:20101213T170000Z 680RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR 681END:AVAILABLE 682END:VAVAILABILITY 683BEGIN:VAVAILABILITY 684PRIORITY:1 685DTSTART:20101214T000000Z 686DTEND:20110107T000000Z 687BUSYTYPE:BUSY 688END:VAVAILABILITY 689END:VCALENDAR 690ICS; 691 692 $this->assertFreeBusyReport( 693 "FREEBUSY:20110101T110000Z/20110103T110000Z", 694 $blob, 695 null, 696 $vavail 697 ); 698 699 } 700 701 /** 702 * This test has the same input as the last, except somebody mixed up the 703 * PRIORITY values. 704 * 705 * The end-result is that the vacation VAVAILABILITY is completely ignored. 706 */ 707 function testVAvailabilityOfficeHoursVacation2() { 708 709 $blob = <<<ICS 710BEGIN:VCALENDAR 711BEGIN:VEVENT 712UID:lalala 713DTSTART:20110101T120000Z 714DTEND:20110101T130000Z 715END:VEVENT 716END:VCALENDAR 717ICS; 718 719 $vavail = <<<ICS 720BEGIN:VCALENDAR 721BEGIN:VAVAILABILITY 722DTSTART:20100101T000000Z 723DTEND:20120101T000000Z 724BUSYTYPE:BUSY-TENTATIVE 725PRIORITY:1 726BEGIN:AVAILABLE 727DTSTART:20101213T090000Z 728DTEND:20101213T170000Z 729RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR 730END:AVAILABLE 731END:VAVAILABILITY 732BEGIN:VAVAILABILITY 733PRIORITY:2 734DTSTART:20101214T000000Z 735DTEND:20110107T000000Z 736BUSYTYPE:BUSY 737END:VAVAILABILITY 738END:VCALENDAR 739ICS; 740 741 $this->assertFreeBusyReport( 742 "FREEBUSY;FBTYPE=BUSY-TENTATIVE:20110101T110000Z/20110101T120000Z\n" . 743 "FREEBUSY:20110101T120000Z/20110101T130000Z\n" . 744 "FREEBUSY;FBTYPE=BUSY-TENTATIVE:20110101T130000Z/20110103T090000Z\n", 745 $blob, 746 null, 747 $vavail 748 ); 749 750 } 751} 752