1<?php 2 3namespace Sabre\VObject\Component; 4 5use DateTimeImmutable; 6use DateTimeZone; 7use Sabre\VObject; 8use Sabre\VObject\Reader; 9 10/** 11 * We use `RFCxxx` has a placeholder for the 12 * https://tools.ietf.org/html/draft-daboo-calendar-availability-05 name. 13 */ 14class VAvailabilityTest extends \PHPUnit_Framework_TestCase { 15 16 function testVAvailabilityComponent() { 17 18 $vcal = <<<VCAL 19BEGIN:VCALENDAR 20BEGIN:VAVAILABILITY 21END:VAVAILABILITY 22END:VCALENDAR 23VCAL; 24 $document = Reader::read($vcal); 25 26 $this->assertInstanceOf(__NAMESPACE__ . '\VAvailability', $document->VAVAILABILITY); 27 28 } 29 30 function testGetEffectiveStartEnd() { 31 32 $vcal = <<<VCAL 33BEGIN:VCALENDAR 34BEGIN:VAVAILABILITY 35DTSTART:20150717T162200Z 36DTEND:20150717T172200Z 37END:VAVAILABILITY 38END:VCALENDAR 39VCAL; 40 41 $document = Reader::read($vcal); 42 $tz = new DateTimeZone('UTC'); 43 $this->assertEquals( 44 [ 45 new DateTimeImmutable('2015-07-17 16:22:00', $tz), 46 new DateTimeImmutable('2015-07-17 17:22:00', $tz), 47 ], 48 $document->VAVAILABILITY->getEffectiveStartEnd() 49 ); 50 51 } 52 53 function testGetEffectiveStartDuration() { 54 55 $vcal = <<<VCAL 56BEGIN:VCALENDAR 57BEGIN:VAVAILABILITY 58DTSTART:20150717T162200Z 59DURATION:PT1H 60END:VAVAILABILITY 61END:VCALENDAR 62VCAL; 63 64 $document = Reader::read($vcal); 65 $tz = new DateTimeZone('UTC'); 66 $this->assertEquals( 67 [ 68 new DateTimeImmutable('2015-07-17 16:22:00', $tz), 69 new DateTimeImmutable('2015-07-17 17:22:00', $tz), 70 ], 71 $document->VAVAILABILITY->getEffectiveStartEnd() 72 ); 73 74 } 75 76 function testGetEffectiveStartEndUnbound() { 77 78 $vcal = <<<VCAL 79BEGIN:VCALENDAR 80BEGIN:VAVAILABILITY 81END:VAVAILABILITY 82END:VCALENDAR 83VCAL; 84 85 $document = Reader::read($vcal); 86 $this->assertEquals( 87 [ 88 null, 89 null, 90 ], 91 $document->VAVAILABILITY->getEffectiveStartEnd() 92 ); 93 94 } 95 96 function testIsInTimeRangeUnbound() { 97 98 $vcal = <<<VCAL 99BEGIN:VCALENDAR 100BEGIN:VAVAILABILITY 101END:VAVAILABILITY 102END:VCALENDAR 103VCAL; 104 105 $document = Reader::read($vcal); 106 $this->assertTrue( 107 $document->VAVAILABILITY->isInTimeRange(new DateTimeImmutable('2015-07-17'), new DateTimeImmutable('2015-07-18')) 108 ); 109 110 } 111 112 function testIsInTimeRangeOutside() { 113 114 $vcal = <<<VCAL 115BEGIN:VCALENDAR 116BEGIN:VAVAILABILITY 117DTSTART:20140101T000000Z 118DTEND:20140102T000000Z 119END:VAVAILABILITY 120END:VCALENDAR 121VCAL; 122 123 $document = Reader::read($vcal); 124 $this->assertFalse( 125 $document->VAVAILABILITY->isInTimeRange(new DateTimeImmutable('2015-07-17'), new DateTimeImmutable('2015-07-18')) 126 ); 127 128 } 129 130 function testRFCxxxSection3_1_availabilityprop_required() { 131 132 // UID and DTSTAMP are present. 133 $this->assertIsValid(Reader::read( 134<<<VCAL 135BEGIN:VCALENDAR 136VERSION:2.0 137PRODID:-//id 138BEGIN:VAVAILABILITY 139UID:foo@test 140DTSTAMP:20111005T133225Z 141END:VAVAILABILITY 142END:VCALENDAR 143VCAL 144 )); 145 146 // UID and DTSTAMP are missing. 147 $this->assertIsNotValid(Reader::read( 148<<<VCAL 149BEGIN:VCALENDAR 150VERSION:2.0 151PRODID:-//id 152BEGIN:VAVAILABILITY 153END:VAVAILABILITY 154END:VCALENDAR 155VCAL 156 )); 157 158 // DTSTAMP is missing. 159 $this->assertIsNotValid(Reader::read( 160<<<VCAL 161BEGIN:VCALENDAR 162VERSION:2.0 163PRODID:-//id 164BEGIN:VAVAILABILITY 165UID:foo@test 166END:VAVAILABILITY 167END:VCALENDAR 168VCAL 169 )); 170 171 // UID is missing. 172 $this->assertIsNotValid(Reader::read( 173<<<VCAL 174BEGIN:VCALENDAR 175VERSION:2.0 176PRODID:-//id 177BEGIN:VAVAILABILITY 178DTSTAMP:20111005T133225Z 179END:VAVAILABILITY 180END:VCALENDAR 181VCAL 182 )); 183 184 } 185 186 function testRFCxxxSection3_1_availabilityprop_optional_once() { 187 188 $properties = [ 189 'BUSYTYPE:BUSY', 190 'CLASS:PUBLIC', 191 'CREATED:20111005T135125Z', 192 'DESCRIPTION:Long bla bla', 193 'DTSTART:20111005T020000', 194 'LAST-MODIFIED:20111005T135325Z', 195 'ORGANIZER:mailto:foo@example.com', 196 'PRIORITY:1', 197 'SEQUENCE:0', 198 'SUMMARY:Bla bla', 199 'URL:http://example.org/' 200 ]; 201 202 // They are all present, only once. 203 $this->assertIsValid(Reader::read($this->template($properties))); 204 205 // We duplicate each one to see if it fails. 206 foreach ($properties as $property) { 207 $this->assertIsNotValid(Reader::read($this->template([ 208 $property, 209 $property 210 ]))); 211 } 212 213 } 214 215 function testRFCxxxSection3_1_availabilityprop_dtend_duration() { 216 217 // Only DTEND. 218 $this->assertIsValid(Reader::read($this->template([ 219 'DTEND:21111005T133225Z' 220 ]))); 221 222 // Only DURATION. 223 $this->assertIsValid(Reader::read($this->template([ 224 'DURATION:PT1H' 225 ]))); 226 227 // Both (not allowed). 228 $this->assertIsNotValid(Reader::read($this->template([ 229 'DTEND:21111005T133225Z', 230 'DURATION:PT1H' 231 ]))); 232 } 233 234 function testAvailableSubComponent() { 235 236 $vcal = <<<VCAL 237BEGIN:VCALENDAR 238BEGIN:VAVAILABILITY 239BEGIN:AVAILABLE 240END:AVAILABLE 241END:VAVAILABILITY 242END:VCALENDAR 243VCAL; 244 $document = Reader::read($vcal); 245 246 $this->assertInstanceOf(__NAMESPACE__, $document->VAVAILABILITY->AVAILABLE); 247 248 } 249 250 function testRFCxxxSection3_1_availableprop_required() { 251 252 // UID, DTSTAMP and DTSTART are present. 253 $this->assertIsValid(Reader::read( 254<<<VCAL 255BEGIN:VCALENDAR 256VERSION:2.0 257PRODID:-//id 258BEGIN:VAVAILABILITY 259UID:foo@test 260DTSTAMP:20111005T133225Z 261BEGIN:AVAILABLE 262UID:foo@test 263DTSTAMP:20111005T133225Z 264DTSTART:20111005T133225Z 265END:AVAILABLE 266END:VAVAILABILITY 267END:VCALENDAR 268VCAL 269 )); 270 271 // UID, DTSTAMP and DTSTART are missing. 272 $this->assertIsNotValid(Reader::read( 273<<<VCAL 274BEGIN:VCALENDAR 275VERSION:2.0 276PRODID:-//id 277BEGIN:VAVAILABILITY 278UID:foo@test 279DTSTAMP:20111005T133225Z 280BEGIN:AVAILABLE 281END:AVAILABLE 282END:VAVAILABILITY 283END:VCALENDAR 284VCAL 285 )); 286 287 // UID is missing. 288 $this->assertIsNotValid(Reader::read( 289<<<VCAL 290BEGIN:VCALENDAR 291VERSION:2.0 292PRODID:-//id 293BEGIN:VAVAILABILITY 294UID:foo@test 295DTSTAMP:20111005T133225Z 296BEGIN:AVAILABLE 297DTSTAMP:20111005T133225Z 298DTSTART:20111005T133225Z 299END:AVAILABLE 300END:VAVAILABILITY 301END:VCALENDAR 302VCAL 303 )); 304 305 // DTSTAMP is missing. 306 $this->assertIsNotValid(Reader::read( 307<<<VCAL 308BEGIN:VCALENDAR 309VERSION:2.0 310PRODID:-//id 311BEGIN:VAVAILABILITY 312UID:foo@test 313DTSTAMP:20111005T133225Z 314BEGIN:AVAILABLE 315UID:foo@test 316DTSTART:20111005T133225Z 317END:AVAILABLE 318END:VAVAILABILITY 319END:VCALENDAR 320VCAL 321 )); 322 323 // DTSTART is missing. 324 $this->assertIsNotValid(Reader::read( 325<<<VCAL 326BEGIN:VCALENDAR 327VERSION:2.0 328PRODID:-//id 329BEGIN:VAVAILABILITY 330UID:foo@test 331DTSTAMP:20111005T133225Z 332BEGIN:AVAILABLE 333UID:foo@test 334DTSTAMP:20111005T133225Z 335END:AVAILABLE 336END:VAVAILABILITY 337END:VCALENDAR 338VCAL 339 )); 340 341 } 342 343 function testRFCxxxSection3_1_available_dtend_duration() { 344 345 // Only DTEND. 346 $this->assertIsValid(Reader::read($this->templateAvailable([ 347 'DTEND:21111005T133225Z' 348 ]))); 349 350 // Only DURATION. 351 $this->assertIsValid(Reader::read($this->templateAvailable([ 352 'DURATION:PT1H' 353 ]))); 354 355 // Both (not allowed). 356 $this->assertIsNotValid(Reader::read($this->templateAvailable([ 357 'DTEND:21111005T133225Z', 358 'DURATION:PT1H' 359 ]))); 360 } 361 362 function testRFCxxxSection3_1_available_optional_once() { 363 364 $properties = [ 365 'CREATED:20111005T135125Z', 366 'DESCRIPTION:Long bla bla', 367 'LAST-MODIFIED:20111005T135325Z', 368 'RECURRENCE-ID;RANGE=THISANDFUTURE:19980401T133000Z', 369 'RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR', 370 'SUMMARY:Bla bla' 371 ]; 372 373 // They are all present, only once. 374 $this->assertIsValid(Reader::read($this->templateAvailable($properties))); 375 376 // We duplicate each one to see if it fails. 377 foreach ($properties as $property) { 378 $this->assertIsNotValid(Reader::read($this->templateAvailable([ 379 $property, 380 $property 381 ]))); 382 } 383 384 } 385 function testRFCxxxSection3_2() { 386 387 $this->assertEquals( 388 'BUSY', 389 Reader::read($this->templateAvailable([ 390 'BUSYTYPE:BUSY' 391 ])) 392 ->VAVAILABILITY 393 ->AVAILABLE 394 ->BUSYTYPE 395 ->getValue() 396 ); 397 398 $this->assertEquals( 399 'BUSY-UNAVAILABLE', 400 Reader::read($this->templateAvailable([ 401 'BUSYTYPE:BUSY-UNAVAILABLE' 402 ])) 403 ->VAVAILABILITY 404 ->AVAILABLE 405 ->BUSYTYPE 406 ->getValue() 407 ); 408 409 $this->assertEquals( 410 'BUSY-TENTATIVE', 411 Reader::read($this->templateAvailable([ 412 'BUSYTYPE:BUSY-TENTATIVE' 413 ])) 414 ->VAVAILABILITY 415 ->AVAILABLE 416 ->BUSYTYPE 417 ->getValue() 418 ); 419 420 } 421 422 protected function assertIsValid(VObject\Document $document) { 423 424 $validationResult = $document->validate(); 425 if ($validationResult) { 426 $messages = array_map(function($item) { return $item['message']; }, $validationResult); 427 $this->fail('Failed to assert that the supplied document is a valid document. Validation messages: ' . implode(', ', $messages)); 428 } 429 $this->assertEmpty($document->validate()); 430 431 } 432 433 protected function assertIsNotValid(VObject\Document $document) { 434 435 $this->assertNotEmpty($document->validate()); 436 437 } 438 439 protected function template(array $properties) { 440 441 return $this->_template( 442 <<<VCAL 443BEGIN:VCALENDAR 444VERSION:2.0 445PRODID:-//id 446BEGIN:VAVAILABILITY 447UID:foo@test 448DTSTAMP:20111005T133225Z 449… 450END:VAVAILABILITY 451END:VCALENDAR 452VCAL 453, 454 $properties 455 ); 456 457 } 458 459 protected function templateAvailable(array $properties) { 460 461 return $this->_template( 462 <<<VCAL 463BEGIN:VCALENDAR 464VERSION:2.0 465PRODID:-//id 466BEGIN:VAVAILABILITY 467UID:foo@test 468DTSTAMP:20111005T133225Z 469BEGIN:AVAILABLE 470UID:foo@test 471DTSTAMP:20111005T133225Z 472DTSTART:20111005T133225Z 473… 474END:AVAILABLE 475END:VAVAILABILITY 476END:VCALENDAR 477VCAL 478, 479 $properties 480 ); 481 482 } 483 484 protected function _template($template, array $properties) { 485 486 return str_replace('…', implode("\r\n", $properties), $template); 487 488 } 489 490} 491