1<?php 2/** 3 * Unit tests Horde_ActiveSync_Message_Appointment objects. 4 * 5 * @author Michael J. Rubinsky <mrubinsk@horde.org> 6 * @category Horde 7 * @package ActiveSync 8 */ 9class Horde_ActiveSync_AppointmentTest extends Horde_Test_Case 10{ 11 12 protected $_oldtz; 13 14 public function setUp() 15 { 16 $this->_oldtz = date_default_timezone_get(); 17 date_default_timezone_set('America/New_York'); 18 } 19 20 public function tearDown() 21 { 22 date_default_timezone_set($this->_oldtz); 23 } 24 25 /** 26 * Checks that setting/getting non-existant properties throws an exception. 27 */ 28 public function testEncoding() 29 { 30 $this->markTestIncomplete('Needs updated fixture.'); 31 $logger = new Horde_ActiveSync_Log_Logger(new Horde_Log_Handler_Null()); 32 33 $appt = new Horde_ActiveSync_Message_Appointment(array('logger' => $logger)); 34 $appt->setSubject('Event Title'); 35 $appt->setBody('Event Description'); 36 $appt->setLocation('Philadelphia, PA'); 37 $start = new Horde_Date('2011-12-01T15:00:00'); 38 $appt->setDatetime(array( 39 'start' => $start, 40 'end' => new Horde_Date('2011-12-01T16:00:00'), 41 'allday' => false) 42 ); 43 $appt->setTimezone($start); 44 $appt->setSensitivity(Horde_ActiveSync_Message_Appointment::SENSITIVITY_PERSONAL); 45 $appt->setBusyStatus(Horde_ActiveSync_Message_Appointment::BUSYSTATUS_BUSY); 46 $appt->setDTStamp($start->timestamp()); 47 48 $stream = fopen('php://memory', 'w+'); 49 $encoder = new Horde_ActiveSync_Wbxml_Encoder($stream); 50 $encoder->setLogger($logger); 51 52 $encoder->startTag(Horde_ActiveSync::SYNC_DATA); 53 $appt->encodeStream($encoder); 54 $encoder->endTag(); 55 $fixture = file_get_contents(__DIR__ . '/fixtures/appointment.wbxml'); 56 rewind($stream); 57 $results = stream_get_contents($stream); 58 fclose($stream); 59 60 // TODO 61 $this->assertEquals($fixture, $results); 62 } 63 64 public function testDecoding() 65 { 66 $logger = new Horde_ActiveSync_Log_Logger(new Horde_Log_Handler_Null()); 67 $stream = fopen(__DIR__ . '/fixtures/appointment.wbxml', 'r+'); 68 $decoder = new Horde_ActiveSync_Wbxml_Decoder($stream); 69 $decoder->setLogger($logger); 70 71 $element = $decoder->getElementStartTag(Horde_ActiveSync::SYNC_DATA); 72 $appt = new Horde_ActiveSync_Message_Appointment(array('logger' => $logger)); 73 $appt->decodeStream($decoder); 74 fclose($stream); 75 $decoder->getElementEndTag(); 76 77 $this->assertEquals('Event Title', $appt->subject); 78 $this->assertEquals('Event Description', $appt->body); 79 $this->assertEquals('Philadelphia, PA', $appt->location); 80 $this->assertEquals(Horde_ActiveSync_Message_Appointment::SENSITIVITY_PERSONAL, (integer)$appt->sensitivity); 81 $this->assertEquals(Horde_ActiveSync_Message_Appointment::BUSYSTATUS_BUSY, (integer)$appt->busystatus); 82 83 $start = clone($appt->starttime); 84 // Ensure it's UTC 85 $this->assertEquals('UTC', $start->timezone); 86 87 //...and correct. 88 $start->setTimezone('America/New_York'); 89 $this->assertEquals('2011-12-01 15:00:00', (string)$start); 90 } 91 92 public function testEncodingRecurrence() 93 { 94 $this->markTestIncomplete('Needs updated fixture.'); 95 $logger = new Horde_ActiveSync_Log_Logger(new Horde_Log_Handler_Null()); 96 97 // Every other week recurrence, on thursday, no end. 98 $r = new Horde_Date_Recurrence('2011-12-01T15:00:00'); 99 $r->setRecurType(Horde_Date_Recurrence::RECUR_WEEKLY); 100 $r->setRecurInterval(2); 101 $r->setRecurOnDay(Horde_Date::MASK_THURSDAY); 102 103 $appt = new Horde_ActiveSync_Message_Appointment(array('logger' => $logger)); 104 $appt->setSubject('Event Title'); 105 $appt->setBody('Event Description'); 106 $appt->setLocation('Philadelphia, PA'); 107 $start = new Horde_Date('2011-12-01T15:00:00'); 108 $appt->setDatetime(array( 109 'start' => $start, 110 'end' => new Horde_Date('2011-12-01T16:00:00'), 111 'allday' => false) 112 ); 113 $appt->setTimezone($start); 114 $appt->setSensitivity(Horde_ActiveSync_Message_Appointment::SENSITIVITY_PERSONAL); 115 $appt->setBusyStatus(Horde_ActiveSync_Message_Appointment::BUSYSTATUS_BUSY); 116 $appt->setDTStamp($start->timestamp()); 117 $appt->setRecurrence($r); 118 119 $stream = fopen('php://memory', 'w+'); 120 $encoder = new Horde_ActiveSync_Wbxml_Encoder($stream); 121 $encoder->setLogger($logger); 122 123 $encoder->startTag(Horde_ActiveSync::SYNC_DATA); 124 $appt->encodeStream($encoder); 125 $encoder->endTag(); 126 $fixture = file_get_contents(__DIR__ . '/fixtures/recurrence.wbxml'); 127 rewind($stream); 128 $results = stream_get_contents($stream); 129 fclose($stream); 130 131 $this->assertEquals($fixture, $results); 132 } 133 134 public function testDecodingRecurrence() 135 { 136 $logger = new Horde_ActiveSync_Log_Logger(new Horde_Log_Handler_Null()); 137 // Test Decoding 138 $stream = fopen(__DIR__ . '/fixtures/recurrence.wbxml', 'r+'); 139 $decoder = new Horde_ActiveSync_Wbxml_Decoder($stream); 140 141 $element = $decoder->getElementStartTag(Horde_ActiveSync::SYNC_DATA); 142 $appt = new Horde_ActiveSync_Message_Appointment(array('logger' => $logger)); 143 $appt->decodeStream($decoder); 144 fclose($stream); 145 $decoder->getElementEndTag(); 146 147 // Same properties that are testing in testDeoding, but test again 148 // here to be sure recurrence doesn't mess up the deocder. 149 $this->assertEquals('Event Title', $appt->subject); 150 $this->assertEquals('Event Description', $appt->body); 151 $this->assertEquals('Philadelphia, PA', $appt->location); 152 $this->assertEquals(Horde_ActiveSync_Message_Appointment::SENSITIVITY_PERSONAL, (integer)$appt->sensitivity); 153 $this->assertEquals(Horde_ActiveSync_Message_Appointment::BUSYSTATUS_BUSY, (integer)$appt->busystatus); 154 $start = clone($appt->starttime); 155 // Ensure it's UTC 156 $this->assertEquals('UTC', $start->timezone); 157 //...and correct. 158 $start->setTimezone('America/New_York'); 159 $this->assertEquals('2011-12-01 15:00:00', (string)$start); 160 161 // Recurrence properties 162 $rrule = $appt->getRecurrence(); 163 $this->assertEquals('2011-12-01 15:00:00', (string)$rrule->getRecurStart()->setTimezone('America/New_York')); 164 $this->assertEquals('', (string)$rrule->getRecurEnd()); 165 $this->assertEquals(Horde_Date_Recurrence::RECUR_WEEKLY, $rrule->getRecurType()); 166 $this->assertEquals(2, $rrule->getRecurInterval()); 167 $this->assertEquals(Horde_Date::MASK_THURSDAY, $days = $rrule->getRecurOnDays()); 168 } 169 170 public function testEncodingSimpleExceptions() 171 { 172 $this->markTestIncomplete('Needs updated fixture.'); 173 $logger = new Horde_ActiveSync_Log_Logger(new Horde_Log_Handler_Null()); 174 175 // Every other week recurrence, on thursday, no end. 176 $r = new Horde_Date_Recurrence('2011-12-01T15:00:00'); 177 $r->setRecurType(Horde_Date_Recurrence::RECUR_WEEKLY); 178 $r->setRecurInterval(2); 179 $r->setRecurOnDay(Horde_Date::MASK_THURSDAY); 180 $r->addException(2011, 12, 29); 181 182 $e = new Horde_ActiveSync_Message_Exception(); 183 $d = new Horde_Date('2011-12-29T15:00:00'); 184 $e->setExceptionStartTime($d); 185 $e->deleted = true; 186 187 $appt = new Horde_ActiveSync_Message_Appointment(array('logger' => $logger)); 188 $appt->setSubject('Event Title'); 189 $appt->setBody('Event Description'); 190 $appt->setLocation('Philadelphia, PA'); 191 $start = new Horde_Date('2011-12-01T15:00:00'); 192 $appt->setDatetime(array( 193 'start' => $start, 194 'end' => new Horde_Date('2011-12-01T16:00:00'), 195 'allday' => false) 196 ); 197 $appt->setTimezone($start); 198 $appt->setSensitivity(Horde_ActiveSync_Message_Appointment::SENSITIVITY_PERSONAL); 199 $appt->setBusyStatus(Horde_ActiveSync_Message_Appointment::BUSYSTATUS_BUSY); 200 $appt->setDTStamp($start->timestamp()); 201 $appt->setRecurrence($r); 202 $appt->addException($e); 203 204 $stream = fopen('php://memory', 'w+'); 205 $encoder = new Horde_ActiveSync_Wbxml_Encoder($stream); 206 $encoder->setLogger($logger); 207 $encoder->startTag(Horde_ActiveSync::SYNC_DATA); 208 $appt->encodeStream($encoder); 209 $encoder->endTag(); 210 211 $fixture = file_get_contents(__DIR__ . '/fixtures/simpleexception.wbxml'); 212 rewind($stream); 213 $results = stream_get_contents($stream); 214 fclose($stream); 215 216 $this->assertEquals($fixture, $results); 217 } 218 219 public function testAlldayEncoding() 220 { 221 $logger = new Horde_ActiveSync_Log_Logger(new Horde_Log_Handler_Null()); 222 223 // Check that the encoded wbxml looks correct. 224 $stream_out = fopen('php://memory', 'w+'); 225 $encoder = new Horde_ActiveSync_Wbxml_Encoder($stream_out); 226 $message = new Horde_ActiveSync_Message_Appointment( 227 array('logger' => $logger, 'protocolversion' => Horde_ActiveSync::VERSION_FOURTEEN) 228 ); 229 $message->setSubject('Test Event'); 230 $message->alldayevent = true; 231 $start = new Horde_Date('1970-03-20T00:00:00', 'America/New_York'); 232 $end = new Horde_Date('1970-03-21T00:00:00', 'America/New_York'); 233 $message->starttime = $start; 234 $message->endtime = $end; 235 $message->setTimezone($start); 236 $message->meetingstatus = Horde_ActiveSync_Message_Appointment::MEETING_NOT_MEETING; 237 $message->encodeStream($encoder); 238 239 $fixture = file_get_contents(__DIR__ . '/fixtures/allday_appointment.wbxml'); 240 rewind($stream_out); 241 $this->assertEquals($fixture, stream_get_contents($stream_out)); 242 243 // Make sure EAS versions work properly. 244 rewind($stream_out); 245 $message = new Horde_ActiveSync_Message_Appointment( 246 array('logger' => $logger, 'protocolversion' => Horde_ActiveSync::VERSION_FOURTEEN) 247 ); 248 $decoder = new Horde_ActiveSync_Wbxml_Decoder($stream_out); 249 $decoder->getElementStartTag(Horde_ActiveSync::SYNC_DATA); 250 $message->decodeStream($decoder); 251 $end = $message->endtime; 252 $end->setTimezone('America/New_York'); 253 $start->setTimezone('America/New_York'); 254 $this->assertEquals('1970-03-21 00:00:00', (string)$end); 255 $this->assertEquals('1970-03-20 00:00:00', (string)$start); 256 257 rewind($stream_out); 258 $message = new Horde_ActiveSync_Message_Appointment( 259 array('logger' => $logger, 'protocolversion' => Horde_ActiveSync::VERSION_SIXTEEN) 260 ); 261 $decoder = new Horde_ActiveSync_Wbxml_Decoder($stream_out); 262 $decoder->getElementStartTag(Horde_ActiveSync::SYNC_DATA); 263 $message->decodeStream($decoder); 264 $end = $message->endtime; 265 $end->setTimezone('America/New_York'); 266 $start->setTimezone('America/New_York'); 267 $this->assertEquals('1970-03-21 00:00:00', (string)$end); 268 $this->assertEquals('1970-03-20 00:00:00', (string)$start); 269 } 270 271 /** 272 * Test deprecated setDatetime method since it's still used in FW_52. 273 */ 274 public function testSetDatetimeAlldayHandling() 275 { 276 $logger = new Horde_ActiveSync_Log_Logger(new Horde_Log_Handler_Null()); 277 278 // Test the deprecated setDatetime method's ability to properly detect 279 // and set properties. 280 // Single day 00:00 to 00:00 281 $message = new Horde_ActiveSync_Message_Appointment( 282 array('logger' => $logger, 'protocolversion' => Horde_ActiveSync::VERSION_FOURTEEN) 283 ); 284 $start = new Horde_Date('1970-03-20T00:00:00', 'America/New_York'); 285 $end = new Horde_Date('1970-03-21T00:00:00', 'America/New_York'); 286 $message->setDatetime(array('start' => $start, 'end' => $end)); 287 $this->assertEquals(true, $message->alldayevent); 288 289 // Multiday 00:00 to 23:59 290 $message = new Horde_ActiveSync_Message_Appointment( 291 array('logger' => $logger, 'protocolversion' => Horde_ActiveSync::VERSION_FOURTEEN) 292 ); 293 $start = new Horde_Date('1970-03-20T00:00:00', 'America/New_York'); 294 $end = new Horde_Date('1970-03-21T23:59:00', 'America/New_York'); 295 $message->setDatetime(array('start' => $start, 'end' => $end)); 296 $this->assertEquals(true, $message->alldayevent); 297 $end = $message->endtime; 298 $end->setTimezone('America/New_York'); 299 $this->assertEquals('1970-03-22 00:00:00', (string)$end); 300 301 // Single day with incorrect time part, no endtime given. 302 $message = new Horde_ActiveSync_Message_Appointment( 303 array('logger' => $logger, 'protocolversion' => Horde_ActiveSync::VERSION_FOURTEEN) 304 ); 305 $start = new Horde_Date('1970-03-20T04:00:00', 'America/New_York'); 306 $message->setDatetime(array('start' => $start, 'allday' => true)); 307 $this->assertEquals(true, $message->alldayevent); 308 $start = $message->starttime; 309 $start->setTimezone('America/New_York'); 310 $this->assertEquals('1970-03-20 00:00:00', (string)$start); 311 $end = $message->endtime; 312 $end->setTimezone('America/New_York'); 313 $this->assertEquals('1970-03-21 00:00:00', (string)$end); 314 315 // Single day, no endtime given. 316 $message = new Horde_ActiveSync_Message_Appointment( 317 array('logger' => $logger, 'protocolversion' => Horde_ActiveSync::VERSION_FOURTEEN) 318 ); 319 $start = new Horde_Date('1970-03-20T00:00:00', 'America/New_York'); 320 $message->setDatetime(array('start' => $start, 'allday' => true)); 321 $this->assertEquals(true, $message->alldayevent); 322 $end = $message->endtime; 323 $end->setTimezone('America/New_York'); 324 $this->assertEquals('1970-03-21 00:00:00', (string)$end); 325 326 // Make sure non-all day events don't inadvertently get converted to one 327 $message = new Horde_ActiveSync_Message_Appointment( 328 array('logger' => $logger, 'protocolversion' => Horde_ActiveSync::VERSION_FOURTEEN) 329 ); 330 $start = new Horde_Date('1970-03-20T05:00:00', 'America/New_York'); 331 $end = new Horde_Date('1970-03-21T00:00:00', 'America/New_York'); 332 $message->setDatetime(array('start' => $start, 'end' => $end)); 333 $this->assertEquals(false, $message->alldayevent); 334 $start = $message->starttime; 335 $start->setTimezone('America/New_York'); 336 $this->assertEquals('1970-03-20 05:00:00', (string)$start); 337 338 // Incorrect timeparts given, but allday flag is set. 339 $message = new Horde_ActiveSync_Message_Appointment( 340 array('logger' => $logger, 'protocolversion' => Horde_ActiveSync::VERSION_FOURTEEN) 341 ); 342 $start = new Horde_Date('1970-03-20T00:00:00', 'America/New_York'); 343 $end = new Horde_Date('1970-03-21T05:00:00', 'America/New_York'); 344 $message->setDatetime(array('start' => $start, 'end' => $end, 'allday' => true)); 345 $this->assertEquals(true, $message->alldayevent); 346 $start = $message->starttime; 347 $start->setTimezone('America/New_York'); 348 $end = $message->endtime; 349 $end->setTimezone('America/New_York'); 350 $this->assertEquals('1970-03-20 00:00:00', (string)$start); 351 $this->assertEquals('1970-03-22 00:00:00', (string)$end); 352 353 $message = new Horde_ActiveSync_Message_Appointment( 354 array('logger' => $logger, 'protocolversion' => Horde_ActiveSync::VERSION_FOURTEEN) 355 ); 356 $start = new Horde_Date('1970-03-20T08:00:00', 'America/New_York'); 357 $end = new Horde_Date('1970-03-21T05:00:00', 'America/New_York'); 358 $message->setDatetime(array('start' => $start, 'end' => $end, 'allday' => true)); 359 $this->assertEquals(true, $message->alldayevent); 360 $start = $message->starttime; 361 $start->setTimezone('America/New_York'); 362 $end = $message->endtime; 363 $end->setTimezone('America/New_York'); 364 $this->assertEquals('1970-03-20 00:00:00', (string)$start); 365 $this->assertEquals('1970-03-22 00:00:00', (string)$end); 366 } 367 368 public function testDecodingSimpleExceptions() 369 { 370 $logger = new Horde_ActiveSync_Log_Logger(new Horde_Log_Handler_Null()); 371 372 // Test Decoding 373 $stream = fopen(__DIR__ . '/fixtures/simpleexception.wbxml', 'r+'); 374 $decoder = new Horde_ActiveSync_Wbxml_Decoder($stream); 375 376 $element = $decoder->getElementStartTag(Horde_ActiveSync::SYNC_DATA); 377 $appt = new Horde_ActiveSync_Message_Appointment(array('logger' => $logger)); 378 $appt->decodeStream($decoder); 379 fclose($stream); 380 $decoder->getElementEndTag(); 381 382 // Same properties that are testing in testDeoding, but test again 383 // here to be sure recurrence doesn't mess up the deocder. 384 $this->assertEquals('Event Title', $appt->subject); 385 $this->assertEquals('Event Description', $appt->body); 386 $this->assertEquals('Philadelphia, PA', $appt->location); 387 $this->assertEquals(Horde_ActiveSync_Message_Appointment::SENSITIVITY_PERSONAL, (integer)$appt->sensitivity); 388 $this->assertEquals(Horde_ActiveSync_Message_Appointment::BUSYSTATUS_BUSY, (integer)$appt->busystatus); 389 $start = clone($appt->starttime); 390 // Ensure it's UTC 391 $this->assertEquals('UTC', $start->timezone); 392 //...and correct. 393 $start->setTimezone('America/New_York'); 394 $this->assertEquals('2011-12-01 15:00:00', (string)$start); 395 396 // Recurrence properties 397 $rrule = $appt->getRecurrence(); 398 $this->assertEquals('2011-12-01 15:00:00', (string)$rrule->getRecurStart()->setTimezone('America/New_York')); 399 $this->assertEquals('', (string)$rrule->getRecurEnd()); 400 $this->assertEquals(Horde_Date_Recurrence::RECUR_WEEKLY, $rrule->getRecurType()); 401 $this->assertEquals(2, $rrule->getRecurInterval()); 402 $this->assertEquals(Horde_Date::MASK_THURSDAY, $days = $rrule->getRecurOnDays()); 403 404 405 // Ensure the exception came over (should have one, deleted exception 406 // on 2011-12-29) 407 $exceptions = $appt->getExceptions(); 408 $e = array_pop($exceptions); 409 $this->assertEquals(true, (boolean)$e->deleted); 410 $dt = $e->getExceptionStartTime(); 411 $rrule->addException($dt->format('Y'), $dt->format('m'), $dt->format('d')); 412 413 // This would normally be 2011-12-29, but that's an exception. 414 $date = $rrule->nextActiveRecurrence(new Horde_Date('2011-12-16')); 415 $this->assertEquals('2012-01-12 15:00:00', (string)$date); 416 } 417 418 public function testRecurrenceDSTSwitch() 419 { 420 // Recurring event starts 10/1/2011 15:00:00 EDST 421 $logger = new Horde_ActiveSync_Log_Logger(new Horde_Log_Handler_Null()); 422 423 // Test Decoding 424 $stream = fopen(__DIR__ . '/fixtures/dst.wbxml', 'r+'); 425 $decoder = new Horde_ActiveSync_Wbxml_Decoder($stream); 426 427 $element = $decoder->getElementStartTag(Horde_ActiveSync::SYNC_DATA); 428 $appt = new Horde_ActiveSync_Message_Appointment(array('logger' => $logger)); 429 $appt->decodeStream($decoder); 430 fclose($stream); 431 $decoder->getElementEndTag(); 432 $rrule = $appt->getRecurrence(); 433 434 // Get the next recurrence, still during EDST 435 $next = $rrule->nextActiveRecurrence(new Horde_Date('2011-10-15')); 436 $this->assertEquals('2011-10-15 15:00:00', (string)$next->setTimezone('America/New_York')); 437 438 // Now get an occurence after the transition to EST. 439 $next = $rrule->nextActiveRecurrence(new Horde_Date('2011-12-01')); 440 $this->assertEquals('2011-12-10 15:00:00', (string)$next->setTimezone('America/New_York')); 441 } 442 443 public function testMissingSupportedTag() 444 { 445 $state = $this->getMockSkipConstructor('Horde_ActiveSync_State_Base'); 446 $fixture = array( 447 'userAgent' => 'Apple-iPad3C6/1202.435', 448 'properties' => array(Horde_ActiveSync_Device::OS => 'iOS 8.1.1') 449 ); 450 $device = new Horde_ActiveSync_Device($state, $fixture); 451 $contact = new Horde_ActiveSync_Message_Appointment(array('device' => $device, 'protocolversion' => Horde_ActiveSync::VERSION_FOURTEEN)); 452 $contact->setSupported(array()); 453 $this->assertEquals(false, $contact->isGhosted('subject')); 454 $this->assertEquals(false, $contact->isGhosted('body')); 455 456 $device = new Horde_ActiveSync_Device($state, $fixture); 457 $contact = new Horde_ActiveSync_Message_Appointment(array('device' => $device, 'protocolversion' => Horde_ActiveSync::VERSION_SIXTEEN)); 458 $contact->setSupported(array()); 459 $this->assertEquals(true, $contact->isGhosted('subject')); 460 $this->assertEquals(true, $contact->isGhosted('body')); 461 } 462 463 public function testEmptySupportedTag() 464 { 465 $state = $this->getMockSkipConstructor('Horde_ActiveSync_State_Base'); 466 $fixture = array( 467 'userAgent' => 'Apple-iPad3C6/1202.435', 468 'properties' => array(Horde_ActiveSync_Device::OS => 'iOS 8.1.1') 469 ); 470 $device = new Horde_ActiveSync_Device($state, $fixture); 471 $contact = new Horde_ActiveSync_Message_Appointment(array('device' => $device, 'protocolversion' => Horde_ActiveSync::VERSION_FOURTEEN)); 472 $contact->setSupported(array(Horde_ActiveSync::ALL_GHOSTED)); 473 $this->assertEquals(true, $contact->isGhosted('subject')); 474 $this->assertEquals(true, $contact->isGhosted('body')); 475 476 $device = new Horde_ActiveSync_Device($state, $fixture); 477 $contact = new Horde_ActiveSync_Message_Appointment(array('device' => $device, 'protocolversion' => Horde_ActiveSync::VERSION_SIXTEEN)); 478 $contact->setSupported(array(Horde_ActiveSync::ALL_GHOSTED)); 479 $this->assertEquals(true, $contact->isGhosted('subject')); 480 $this->assertEquals(true, $contact->isGhosted('body')); 481 } 482 483} 484