Mercurial > hg > rc1
comparison plugins/libcalendaring/tests/libvcalendar.php @ 4:888e774ee983
libcalendar plugin as distributed
| author | Charlie Root |
|---|---|
| date | Sat, 13 Jan 2018 08:57:56 -0500 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 3:f6fe4b6ae66a | 4:888e774ee983 |
|---|---|
| 1 <?php | |
| 2 | |
| 3 /** | |
| 4 * libcalendaring plugin's iCalendar functions tests | |
| 5 * | |
| 6 * @author Thomas Bruederli <bruederli@kolabsys.com> | |
| 7 * | |
| 8 * Copyright (C) 2014, Kolab Systems AG <contact@kolabsys.com> | |
| 9 * | |
| 10 * This program is free software: you can redistribute it and/or modify | |
| 11 * it under the terms of the GNU Affero General Public License as | |
| 12 * published by the Free Software Foundation, either version 3 of the | |
| 13 * License, or (at your option) any later version. | |
| 14 * | |
| 15 * This program is distributed in the hope that it will be useful, | |
| 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 18 * GNU Affero General Public License for more details. | |
| 19 * | |
| 20 * You should have received a copy of the GNU Affero General Public License | |
| 21 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| 22 */ | |
| 23 | |
| 24 class libvcalendar_test extends PHPUnit_Framework_TestCase | |
| 25 { | |
| 26 function setUp() | |
| 27 { | |
| 28 require_once __DIR__ . '/../libvcalendar.php'; | |
| 29 require_once __DIR__ . '/../libcalendaring.php'; | |
| 30 } | |
| 31 | |
| 32 /** | |
| 33 * Simple iCal parsing test | |
| 34 */ | |
| 35 function test_import() | |
| 36 { | |
| 37 $ical = new libvcalendar(); | |
| 38 $ics = file_get_contents(__DIR__ . '/resources/snd.ics'); | |
| 39 $events = $ical->import($ics, 'UTF-8'); | |
| 40 | |
| 41 $this->assertEquals(1, count($events)); | |
| 42 $event = $events[0]; | |
| 43 | |
| 44 $this->assertInstanceOf('DateTime', $event['created'], "'created' property is DateTime object"); | |
| 45 $this->assertInstanceOf('DateTime', $event['changed'], "'changed' property is DateTime object"); | |
| 46 $this->assertEquals('UTC', $event['created']->getTimezone()->getName(), "'created' date is in UTC"); | |
| 47 | |
| 48 $this->assertInstanceOf('DateTime', $event['start'], "'start' property is DateTime object"); | |
| 49 $this->assertInstanceOf('DateTime', $event['end'], "'end' property is DateTime object"); | |
| 50 $this->assertEquals('08-01', $event['start']->format('m-d'), "Start date is August 1st"); | |
| 51 $this->assertTrue($event['allday'], "All-day event flag"); | |
| 52 | |
| 53 $this->assertEquals('B968B885-08FB-40E5-B89E-6DA05F26AA79', $event['uid'], "Event UID"); | |
| 54 $this->assertEquals('Swiss National Day', $event['title'], "Event title"); | |
| 55 $this->assertEquals('http://en.wikipedia.org/wiki/Swiss_National_Day', $event['url'], "URL property"); | |
| 56 $this->assertEquals(2, $event['sequence'], "Sequence number"); | |
| 57 | |
| 58 $desclines = explode("\n", $event['description']); | |
| 59 $this->assertEquals(4, count($desclines), "Multiline description"); | |
| 60 $this->assertEquals("French: FĂȘte nationale Suisse", rtrim($desclines[1]), "UTF-8 encoding"); | |
| 61 } | |
| 62 | |
| 63 /** | |
| 64 * Test parsing from files | |
| 65 */ | |
| 66 function test_import_from_file() | |
| 67 { | |
| 68 $ical = new libvcalendar(); | |
| 69 | |
| 70 $events = $ical->import_from_file(__DIR__ . '/resources/multiple.ics', 'UTF-8'); | |
| 71 $this->assertEquals(2, count($events)); | |
| 72 | |
| 73 $events = $ical->import_from_file(__DIR__ . '/resources/invalid.txt', 'UTF-8'); | |
| 74 $this->assertEmpty($events); | |
| 75 } | |
| 76 | |
| 77 /** | |
| 78 * Test parsing from files with multiple VCALENDAR blocks (#2884) | |
| 79 */ | |
| 80 function test_import_from_file_multiple() | |
| 81 { | |
| 82 $ical = new libvcalendar(); | |
| 83 $ical->fopen(__DIR__ . '/resources/multiple-rdate.ics', 'UTF-8'); | |
| 84 $events = array(); | |
| 85 foreach ($ical as $event) { | |
| 86 $events[] = $event; | |
| 87 } | |
| 88 | |
| 89 $this->assertEquals(2, count($events)); | |
| 90 $this->assertEquals("AAAA6A8C3CCE4EE2C1257B5C00FFFFFF-Lotus_Notes_Generated", $events[0]['uid']); | |
| 91 $this->assertEquals("AAAA1C572093EC3FC125799C004AFFFF-Lotus_Notes_Generated", $events[1]['uid']); | |
| 92 } | |
| 93 | |
| 94 function test_invalid_dates() | |
| 95 { | |
| 96 $ical = new libvcalendar(); | |
| 97 $events = $ical->import_from_file(__DIR__ . '/resources/invalid-dates.ics', 'UTF-8'); | |
| 98 $event = $events[0]; | |
| 99 | |
| 100 $this->assertEquals(1, count($events), "Import event data"); | |
| 101 $this->assertInstanceOf('DateTime', $event['created'], "Created date field"); | |
| 102 $this->assertFalse(array_key_exists('changed', $event), "No changed date field"); | |
| 103 } | |
| 104 | |
| 105 function test_invalid_vevent() | |
| 106 { | |
| 107 $this->setExpectedException('\Sabre\VObject\ParseException'); | |
| 108 | |
| 109 $ical = new libvcalendar(); | |
| 110 $events = $ical->import_from_file(__DIR__ . '/resources/invalid-event.ics', 'UTF-8', true); | |
| 111 } | |
| 112 | |
| 113 /** | |
| 114 * Test some extended ical properties such as attendees, recurrence rules, alarms and attachments | |
| 115 */ | |
| 116 function test_extended() | |
| 117 { | |
| 118 $ical = new libvcalendar(); | |
| 119 | |
| 120 $events = $ical->import_from_file(__DIR__ . '/resources/itip.ics', 'UTF-8'); | |
| 121 $event = $events[0]; | |
| 122 $this->assertEquals('REQUEST', $ical->method, "iTip method"); | |
| 123 | |
| 124 // attendees | |
| 125 $this->assertEquals(3, count($event['attendees']), "Attendees list (including organizer)"); | |
| 126 $organizer = $event['attendees'][0]; | |
| 127 $this->assertEquals('ORGANIZER', $organizer['role'], 'Organizer ROLE'); | |
| 128 $this->assertEquals('Rolf Test', $organizer['name'], 'Organizer name'); | |
| 129 | |
| 130 $attendee = $event['attendees'][1]; | |
| 131 $this->assertEquals('REQ-PARTICIPANT', $attendee['role'], 'Attendee ROLE'); | |
| 132 $this->assertEquals('NEEDS-ACTION', $attendee['status'], 'Attendee STATUS'); | |
| 133 $this->assertEquals('rolf2@mykolab.com', $attendee['email'], 'Attendee mailto:'); | |
| 134 $this->assertEquals('carl@mykolab.com', $attendee['delegated-from'], 'Attendee delegated-from'); | |
| 135 $this->assertTrue($attendee['rsvp'], 'Attendee RSVP'); | |
| 136 | |
| 137 $delegator = $event['attendees'][2]; | |
| 138 $this->assertEquals('NON-PARTICIPANT', $delegator['role'], 'Delegator ROLE'); | |
| 139 $this->assertEquals('DELEGATED', $delegator['status'], 'Delegator STATUS'); | |
| 140 $this->assertEquals('INDIVIDUAL', $delegator['cutype'], 'Delegator CUTYPE'); | |
| 141 $this->assertEquals('carl@mykolab.com', $delegator['email'], 'Delegator mailto:'); | |
| 142 $this->assertEquals('rolf2@mykolab.com', $delegator['delegated-to'], 'Delegator delegated-to'); | |
| 143 $this->assertFalse($delegator['rsvp'], 'Delegator RSVP'); | |
| 144 | |
| 145 // attachments | |
| 146 $this->assertEquals(1, count($event['attachments']), "Embedded attachments"); | |
| 147 $attachment = $event['attachments'][0]; | |
| 148 $this->assertEquals('text/html', $attachment['mimetype'], "Attachment mimetype attribute"); | |
| 149 $this->assertEquals('calendar.html', $attachment['name'], "Attachment filename (X-LABEL) attribute"); | |
| 150 $this->assertContains('<title>Kalender</title>', $attachment['data'], "Attachment content (decoded)"); | |
| 151 | |
| 152 // recurrence rules | |
| 153 $events = $ical->import_from_file(__DIR__ . '/resources/recurring.ics', 'UTF-8'); | |
| 154 $event = $events[0]; | |
| 155 | |
| 156 $this->assertTrue(is_array($event['recurrence']), 'Recurrences rule as hash array'); | |
| 157 $rrule = $event['recurrence']; | |
| 158 $this->assertEquals('MONTHLY', $rrule['FREQ'], "Recurrence frequency"); | |
| 159 $this->assertEquals('1', $rrule['INTERVAL'], "Recurrence interval"); | |
| 160 $this->assertEquals('3WE', $rrule['BYDAY'], "Recurrence frequency"); | |
| 161 $this->assertInstanceOf('DateTime', $rrule['UNTIL'], "Recurrence end date"); | |
| 162 | |
| 163 $this->assertEquals(2, count($rrule['EXDATE']), "Recurrence EXDATEs"); | |
| 164 $this->assertInstanceOf('DateTime', $rrule['EXDATE'][0], "Recurrence EXDATE as DateTime"); | |
| 165 | |
| 166 $this->assertTrue(is_array($rrule['EXCEPTIONS'])); | |
| 167 $this->assertEquals(1, count($rrule['EXCEPTIONS']), "Recurrence Exceptions"); | |
| 168 | |
| 169 $exception = $rrule['EXCEPTIONS'][0]; | |
| 170 $this->assertEquals($event['uid'], $event['uid'], "Exception UID"); | |
| 171 $this->assertEquals('Recurring Test (Exception)', $exception['title'], "Exception title"); | |
| 172 $this->assertInstanceOf('DateTime', $exception['start'], "Exception start"); | |
| 173 | |
| 174 // categories, class | |
| 175 $this->assertEquals('libcalendaring tests', join(',', (array)$event['categories']), "Event categories"); | |
| 176 $this->assertEquals('confidential', $event['sensitivity'], "Class/sensitivity = confidential"); | |
| 177 | |
| 178 // parse a recurrence chain instance | |
| 179 $events = $ical->import_from_file(__DIR__ . '/resources/recurrence-id.ics', 'UTF-8'); | |
| 180 $this->assertEquals(1, count($events), "Fall back to Component::getComponents() when getBaseComponents() is empty"); | |
| 181 $this->assertInstanceOf('DateTime', $events[0]['recurrence_date'], "Recurrence-ID as date"); | |
| 182 $this->assertTrue($events[0]['thisandfuture'], "Range=THISANDFUTURE"); | |
| 183 | |
| 184 $this->assertEquals(count($events[0]['exceptions']), 1, "Second VEVENT as exception"); | |
| 185 $this->assertEquals($events[0]['exceptions'][0]['uid'], $events[0]['uid'], "Exception UID match"); | |
| 186 $this->assertEquals($events[0]['exceptions'][0]['sequence'], '2', "Exception sequence"); | |
| 187 } | |
| 188 | |
| 189 /** | |
| 190 * | |
| 191 */ | |
| 192 function test_alarms() | |
| 193 { | |
| 194 $ical = new libvcalendar(); | |
| 195 | |
| 196 $events = $ical->import_from_file(__DIR__ . '/resources/recurring.ics', 'UTF-8'); | |
| 197 $event = $events[0]; | |
| 198 | |
| 199 $this->assertEquals('-12H:DISPLAY', $event['alarms'], "Serialized alarms string"); | |
| 200 $alarm = libcalendaring::parse_alarm_value($event['alarms']); | |
| 201 $this->assertEquals('12', $alarm[0], "Alarm value"); | |
| 202 $this->assertEquals('-H', $alarm[1], "Alarm unit"); | |
| 203 | |
| 204 $this->assertEquals('DISPLAY', $event['valarms'][0]['action'], "Full alarm item (action)"); | |
| 205 $this->assertEquals('-PT12H', $event['valarms'][0]['trigger'], "Full alarm item (trigger)"); | |
| 206 $this->assertEquals('END', $event['valarms'][0]['related'], "Full alarm item (related)"); | |
| 207 | |
| 208 // alarm trigger with 0 values | |
| 209 $events = $ical->import_from_file(__DIR__ . '/resources/alarms.ics', 'UTF-8'); | |
| 210 $event = $events[0]; | |
| 211 | |
| 212 $this->assertEquals('-30M:DISPLAY', $event['alarms'], "Stripped alarm string"); | |
| 213 $alarm = libcalendaring::parse_alarm_value($event['alarms']); | |
| 214 $this->assertEquals('30', $alarm[0], "Alarm value"); | |
| 215 $this->assertEquals('-M', $alarm[1], "Alarm unit"); | |
| 216 $this->assertEquals('-30M', $alarm[2], "Alarm string"); | |
| 217 $this->assertEquals('-PT30M', $alarm[3], "Unified alarm string (stripped zero-values)"); | |
| 218 | |
| 219 $this->assertEquals('DISPLAY', $event['valarms'][0]['action'], "First alarm action"); | |
| 220 $this->assertEquals('', $event['valarms'][0]['related'], "First alarm related property"); | |
| 221 $this->assertEquals('This is the first event reminder', $event['valarms'][0]['description'], "First alarm text"); | |
| 222 | |
| 223 $this->assertEquals(3, count($event['valarms']), "List all VALARM blocks"); | |
| 224 | |
| 225 $valarm = $event['valarms'][1]; | |
| 226 $this->assertEquals(1, count($valarm['attendees']), "Email alarm attendees"); | |
| 227 $this->assertEquals('EMAIL', $valarm['action'], "Second alarm item (action)"); | |
| 228 $this->assertEquals('-P1D', $valarm['trigger'], "Second alarm item (trigger)"); | |
| 229 $this->assertEquals('This is the reminder message', $valarm['summary'], "Email alarm text"); | |
| 230 $this->assertInstanceOf('DateTime', $event['valarms'][2]['trigger'], "Absolute trigger date/time"); | |
| 231 | |
| 232 // test alarms export | |
| 233 $ics = $ical->export(array($event)); | |
| 234 $this->assertContains('ACTION:DISPLAY', $ics, "Display alarm block"); | |
| 235 $this->assertContains('ACTION:EMAIL', $ics, "Email alarm block"); | |
| 236 $this->assertContains('DESCRIPTION:This is the first event reminder', $ics, "Alarm description"); | |
| 237 $this->assertContains('SUMMARY:This is the reminder message', $ics, "Email alarm summary"); | |
| 238 $this->assertContains('ATTENDEE:mailto:reminder-recipient@example.org', $ics, "Email alarm recipient"); | |
| 239 $this->assertContains('TRIGGER;VALUE=DATE-TIME:20130812', $ics, "Date-Time trigger"); | |
| 240 } | |
| 241 | |
| 242 /** | |
| 243 * @depends test_import_from_file | |
| 244 */ | |
| 245 function test_attachment() | |
| 246 { | |
| 247 $ical = new libvcalendar(); | |
| 248 | |
| 249 $events = $ical->import_from_file(__DIR__ . '/resources/attachment.ics', 'UTF-8'); | |
| 250 $event = $events[0]; | |
| 251 | |
| 252 $this->assertEquals(2, count($events)); | |
| 253 $this->assertEquals(1, count($event['attachments'])); | |
| 254 $this->assertEquals('image/png', $event['attachments'][0]['mimetype']); | |
| 255 $this->assertEquals('500px-Opensource.svg.png', $event['attachments'][0]['name']); | |
| 256 } | |
| 257 | |
| 258 /** | |
| 259 * @depends test_import | |
| 260 */ | |
| 261 function test_apple_alarms() | |
| 262 { | |
| 263 $ical = new libvcalendar(); | |
| 264 $events = $ical->import_from_file(__DIR__ . '/resources/apple-alarms.ics', 'UTF-8'); | |
| 265 $event = $events[0]; | |
| 266 | |
| 267 // alarms | |
| 268 $this->assertEquals('-45M:AUDIO', $event['alarms'], "Relative alarm string"); | |
| 269 $alarm = libcalendaring::parse_alarm_value($event['alarms']); | |
| 270 $this->assertEquals('45', $alarm[0], "Alarm value"); | |
| 271 $this->assertEquals('-M', $alarm[1], "Alarm unit"); | |
| 272 | |
| 273 $this->assertEquals(1, count($event['valarms']), "Ignore invalid alarm blocks"); | |
| 274 $this->assertEquals('AUDIO', $event['valarms'][0]['action'], "Full alarm item (action)"); | |
| 275 $this->assertEquals('-PT45M', $event['valarms'][0]['trigger'], "Full alarm item (trigger)"); | |
| 276 $this->assertEquals('Basso', $event['valarms'][0]['uri'], "Full alarm item (attachment)"); | |
| 277 } | |
| 278 | |
| 279 /** | |
| 280 * | |
| 281 */ | |
| 282 function test_escaped_values() | |
| 283 { | |
| 284 $ical = new libvcalendar(); | |
| 285 $events = $ical->import_from_file(__DIR__ . '/resources/escaped.ics', 'UTF-8'); | |
| 286 $event = $events[0]; | |
| 287 | |
| 288 $this->assertEquals("House, Street, Zip Place", $event['location'], "Decode escaped commas in location value"); | |
| 289 $this->assertEquals("Me, meets Them\nThem, meet Me", $event['description'], "Decode description value"); | |
| 290 $this->assertEquals("Kolab, Thomas", $event['attendees'][3]['name'], "Unescaped"); | |
| 291 | |
| 292 $ics = $ical->export($events); | |
| 293 $this->assertContains('ATTENDEE;CN="Kolab, Thomas";PARTSTAT=', $ics, "Quoted attendee parameters"); | |
| 294 } | |
| 295 | |
| 296 /** | |
| 297 * Parse RDATE properties (#2885) | |
| 298 */ | |
| 299 function test_rdate() | |
| 300 { | |
| 301 $ical = new libvcalendar(); | |
| 302 $events = $ical->import_from_file(__DIR__ . '/resources/multiple-rdate.ics', 'UTF-8'); | |
| 303 $event = $events[0]; | |
| 304 | |
| 305 $this->assertEquals(9, count($event['recurrence']['RDATE'])); | |
| 306 $this->assertInstanceOf('DateTime', $event['recurrence']['RDATE'][0]); | |
| 307 $this->assertInstanceOf('DateTime', $event['recurrence']['RDATE'][1]); | |
| 308 } | |
| 309 | |
| 310 /** | |
| 311 * @depends test_import | |
| 312 */ | |
| 313 function test_freebusy() | |
| 314 { | |
| 315 $ical = new libvcalendar(); | |
| 316 $ical->import_from_file(__DIR__ . '/resources/freebusy.ifb', 'UTF-8'); | |
| 317 $freebusy = $ical->freebusy; | |
| 318 | |
| 319 $this->assertInstanceOf('DateTime', $freebusy['start'], "'start' property is DateTime object"); | |
| 320 $this->assertInstanceOf('DateTime', $freebusy['end'], "'end' property is DateTime object"); | |
| 321 $this->assertEquals(11, count($freebusy['periods']), "Number of freebusy periods defined"); | |
| 322 $periods = $ical->get_busy_periods(); | |
| 323 $this->assertEquals(9, count($periods), "Number of busy periods found"); | |
| 324 $this->assertEquals('BUSY-TENTATIVE', $periods[8][2], "FBTYPE=BUSY-TENTATIVE"); | |
| 325 } | |
| 326 | |
| 327 /** | |
| 328 * @depends test_import | |
| 329 */ | |
| 330 function test_freebusy_dummy() | |
| 331 { | |
| 332 $ical = new libvcalendar(); | |
| 333 $ical->import_from_file(__DIR__ . '/resources/dummy.ifb', 'UTF-8'); | |
| 334 $freebusy = $ical->freebusy; | |
| 335 | |
| 336 $this->assertEquals(0, count($freebusy['periods']), "Ignore 0-length freebudy periods"); | |
| 337 $this->assertContains('dummy', $freebusy['comment'], "Parse comment"); | |
| 338 } | |
| 339 | |
| 340 function test_vtodo() | |
| 341 { | |
| 342 $ical = new libvcalendar(); | |
| 343 $tasks = $ical->import_from_file(__DIR__ . '/resources/vtodo.ics', 'UTF-8', true); | |
| 344 $task = $tasks[0]; | |
| 345 | |
| 346 $this->assertInstanceOf('DateTime', $task['start'], "'start' property is DateTime object"); | |
| 347 $this->assertInstanceOf('DateTime', $task['due'], "'due' property is DateTime object"); | |
| 348 $this->assertEquals('-1D:DISPLAY', $task['alarms'], "Taks alarm value"); | |
| 349 $this->assertEquals('IN-PROCESS', $task['status'], "Task status property"); | |
| 350 $this->assertEquals(1, count($task['x-custom']), "Custom properties"); | |
| 351 $this->assertEquals(4, count($task['categories'])); | |
| 352 $this->assertEquals('1234567890-12345678-PARENT', $task['parent_id'], "Parent Relation"); | |
| 353 | |
| 354 $completed = $tasks[1]; | |
| 355 $this->assertEquals('COMPLETED', $completed['status'], "Task status=completed when COMPLETED property is present"); | |
| 356 $this->assertEquals(100, $completed['complete'], "Task percent complete value"); | |
| 357 | |
| 358 $ics = $ical->export(array($completed)); | |
| 359 $this->assertRegExp('/COMPLETED(;VALUE=DATE-TIME)?:[0-9TZ]+/', $ics, "Export COMPLETED property"); | |
| 360 } | |
| 361 | |
| 362 /** | |
| 363 * Test for iCal export from internal hash array representation | |
| 364 * | |
| 365 * | |
| 366 */ | |
| 367 function test_export() | |
| 368 { | |
| 369 $ical = new libvcalendar(); | |
| 370 | |
| 371 $events = $ical->import_from_file(__DIR__ . '/resources/itip.ics', 'UTF-8'); | |
| 372 $event = $events[0]; | |
| 373 $events = $ical->import_from_file(__DIR__ . '/resources/recurring.ics', 'UTF-8'); | |
| 374 $event += $events[0]; | |
| 375 | |
| 376 $this->attachment_data = $event['attachments'][0]['data']; | |
| 377 unset($event['attachments'][0]['data']); | |
| 378 $event['attachments'][0]['id'] = '1'; | |
| 379 $event['description'] = '*Exported by libvcalendar*'; | |
| 380 | |
| 381 $event['start']->setTimezone(new DateTimezone('America/Montreal')); | |
| 382 $event['end']->setTimezone(new DateTimezone('Europe/Berlin')); | |
| 383 | |
| 384 $ics = $ical->export(array($event), 'REQUEST', false, array($this, 'get_attachment_data'), true); | |
| 385 | |
| 386 $this->assertContains('BEGIN:VCALENDAR', $ics, "VCALENDAR encapsulation BEGIN"); | |
| 387 | |
| 388 $this->assertContains('BEGIN:VTIMEZONE', $ics, "VTIMEZONE encapsulation BEGIN"); | |
| 389 $this->assertContains('TZID:Europe/Berlin', $ics, "Timezone ID"); | |
| 390 $this->assertContains('TZOFFSETFROM:+0100', $ics, "Timzone transition FROM"); | |
| 391 $this->assertContains('TZOFFSETTO:+0200', $ics, "Timzone transition TO"); | |
| 392 $this->assertContains('TZOFFSETFROM:-0400', $ics, "TZOFFSETFROM with negative offset (Bug T428)"); | |
| 393 $this->assertContains('TZOFFSETTO:-0500', $ics, "TZOFFSETTO with negative offset (Bug T428)"); | |
| 394 $this->assertContains('END:VTIMEZONE', $ics, "VTIMEZONE encapsulation END"); | |
| 395 | |
| 396 $this->assertContains('BEGIN:VEVENT', $ics, "VEVENT encapsulation BEGIN"); | |
| 397 $this->assertSame(2, substr_count($ics, 'DTSTAMP'), "Duplicate DTSTAMP (T1148)"); | |
| 398 $this->assertContains('UID:ac6b0aee-2519-4e5c-9a25-48c57064c9f0', $ics, "Event UID"); | |
| 399 $this->assertContains('SEQUENCE:' . $event['sequence'], $ics, "Export Sequence number"); | |
| 400 $this->assertContains('CLASS:CONFIDENTIAL', $ics, "Sensitivity => Class"); | |
| 401 $this->assertContains('DESCRIPTION:*Exported by', $ics, "Export Description"); | |
| 402 $this->assertContains('ORGANIZER;CN=Rolf Test:mailto:rolf@', $ics, "Export organizer"); | |
| 403 $this->assertRegExp('/ATTENDEE.*;ROLE=REQ-PARTICIPANT/', $ics, "Export Attendee ROLE"); | |
| 404 $this->assertRegExp('/ATTENDEE.*;PARTSTAT=NEEDS-ACTION/', $ics, "Export Attendee Status"); | |
| 405 $this->assertRegExp('/ATTENDEE.*;RSVP=TRUE/', $ics, "Export Attendee RSVP"); | |
| 406 $this->assertRegExp('/:mailto:rolf2@/', $ics, "Export Attendee mailto:"); | |
| 407 | |
| 408 $rrule = $event['recurrence']; | |
| 409 $this->assertRegExp('/RRULE:.*FREQ='.$rrule['FREQ'].'/', $ics, "Export Recurrence Frequence"); | |
| 410 $this->assertRegExp('/RRULE:.*INTERVAL='.$rrule['INTERVAL'].'/', $ics, "Export Recurrence Interval"); | |
| 411 $this->assertRegExp('/RRULE:.*UNTIL=20140718T215959Z/', $ics, "Export Recurrence End date"); | |
| 412 $this->assertRegExp('/RRULE:.*BYDAY='.$rrule['BYDAY'].'/', $ics, "Export Recurrence BYDAY"); | |
| 413 $this->assertRegExp('/EXDATE.*:20131218/', $ics, "Export Recurrence EXDATE"); | |
| 414 | |
| 415 $this->assertContains('BEGIN:VALARM', $ics, "Export VALARM"); | |
| 416 $this->assertContains('TRIGGER;RELATED=END:-PT12H', $ics, "Export Alarm trigger"); | |
| 417 | |
| 418 $this->assertRegExp('/ATTACH.*;VALUE=BINARY/', $ics, "Embed attachment"); | |
| 419 $this->assertRegExp('/ATTACH.*;ENCODING=BASE64/', $ics, "Attachment B64 encoding"); | |
| 420 $this->assertRegExp('!ATTACH.*;FMTTYPE=text/html!', $ics, "Attachment mimetype"); | |
| 421 $this->assertRegExp('!ATTACH.*;X-LABEL=calendar.html!', $ics, "Attachment filename with X-LABEL"); | |
| 422 | |
| 423 $this->assertContains('END:VEVENT', $ics, "VEVENT encapsulation END"); | |
| 424 $this->assertContains('END:VCALENDAR', $ics, "VCALENDAR encapsulation END"); | |
| 425 } | |
| 426 | |
| 427 /** | |
| 428 * @depends test_extended | |
| 429 * @depends test_export | |
| 430 */ | |
| 431 function test_export_multiple() | |
| 432 { | |
| 433 $ical = new libvcalendar(); | |
| 434 $events = array_merge( | |
| 435 $ical->import_from_file(__DIR__ . '/resources/snd.ics', 'UTF-8'), | |
| 436 $ical->import_from_file(__DIR__ . '/resources/multiple.ics', 'UTF-8') | |
| 437 ); | |
| 438 | |
| 439 $num = count($events); | |
| 440 $ics = $ical->export($events, null, false); | |
| 441 | |
| 442 $this->assertContains('BEGIN:VCALENDAR', $ics, "VCALENDAR encapsulation BEGIN"); | |
| 443 $this->assertContains('END:VCALENDAR', $ics, "VCALENDAR encapsulation END"); | |
| 444 $this->assertEquals($num, substr_count($ics, 'BEGIN:VEVENT'), "VEVENT encapsulation BEGIN"); | |
| 445 $this->assertEquals($num, substr_count($ics, 'END:VEVENT'), "VEVENT encapsulation END"); | |
| 446 } | |
| 447 | |
| 448 /** | |
| 449 * @depends test_export | |
| 450 */ | |
| 451 function test_export_recurrence_exceptions() | |
| 452 { | |
| 453 $ical = new libvcalendar(); | |
| 454 $events = $ical->import_from_file(__DIR__ . '/resources/recurring.ics', 'UTF-8'); | |
| 455 | |
| 456 // add exceptions | |
| 457 $event = $events[0]; | |
| 458 unset($event['recurrence']['EXCEPTIONS']); | |
| 459 | |
| 460 $exception1 = $event; | |
| 461 $exception1['start'] = clone $event['start']; | |
| 462 $exception1['start']->setDate(2013, 8, 14); | |
| 463 $exception1['end'] = clone $event['end']; | |
| 464 $exception1['end']->setDate(2013, 8, 14); | |
| 465 | |
| 466 $exception2 = $event; | |
| 467 $exception2['start'] = clone $event['start']; | |
| 468 $exception2['start']->setDate(2013, 11, 13); | |
| 469 $exception2['end'] = clone $event['end']; | |
| 470 $exception2['end']->setDate(2013, 11, 13); | |
| 471 $exception2['title'] = 'Recurring Exception'; | |
| 472 | |
| 473 $events[0]['recurrence']['EXCEPTIONS'] = array($exception1, $exception2); | |
| 474 | |
| 475 $ics = $ical->export($events, null, false); | |
| 476 | |
| 477 $num = count($events[0]['recurrence']['EXCEPTIONS']) + 1; | |
| 478 $this->assertEquals($num, substr_count($ics, 'BEGIN:VEVENT'), "VEVENT encapsulation BEGIN"); | |
| 479 $this->assertEquals($num, substr_count($ics, 'UID:'.$event['uid']), "Recurrence Exceptions with same UID"); | |
| 480 $this->assertEquals($num, substr_count($ics, 'END:VEVENT'), "VEVENT encapsulation END"); | |
| 481 | |
| 482 $this->assertContains('RECURRENCE-ID;TZID=Europe/Zurich:20130814', $ics, "Recurrence-ID (1) being the exception date"); | |
| 483 $this->assertContains('RECURRENCE-ID;TZID=Europe/Zurich:20131113', $ics, "Recurrence-ID (2) being the exception date"); | |
| 484 $this->assertContains('SUMMARY:'.$exception2['title'], $ics, "Exception title"); | |
| 485 } | |
| 486 | |
| 487 function test_export_valid_rrules() | |
| 488 { | |
| 489 $event = array( | |
| 490 'uid' => '1234567890', | |
| 491 'start' => new DateTime('now'), | |
| 492 'end' => new DateTime('now + 30min'), | |
| 493 'title' => 'test_export_valid_rrules', | |
| 494 'recurrence' => array( | |
| 495 'FREQ' => 'DAILY', | |
| 496 'COUNT' => 5, | |
| 497 'EXDATE' => array(), | |
| 498 'RDATE' => array(), | |
| 499 ), | |
| 500 ); | |
| 501 $ical = new libvcalendar(); | |
| 502 $ics = $ical->export(array($event), null, false, null, false); | |
| 503 | |
| 504 $this->assertNotContains('EXDATE=', $ics); | |
| 505 $this->assertNotContains('RDATE=', $ics); | |
| 506 } | |
| 507 | |
| 508 /** | |
| 509 * | |
| 510 */ | |
| 511 function test_export_rdate() | |
| 512 { | |
| 513 $ical = new libvcalendar(); | |
| 514 $events = $ical->import_from_file(__DIR__ . '/resources/multiple-rdate.ics', 'UTF-8'); | |
| 515 $ics = $ical->export($events, null, false); | |
| 516 | |
| 517 $this->assertContains('RDATE:20140520T020000Z', $ics, "VALUE=PERIOD is translated into single DATE-TIME values"); | |
| 518 } | |
| 519 | |
| 520 /** | |
| 521 * @depends test_export | |
| 522 */ | |
| 523 function test_export_direct() | |
| 524 { | |
| 525 $ical = new libvcalendar(); | |
| 526 $events = $ical->import_from_file(__DIR__ . '/resources/multiple.ics', 'UTF-8'); | |
| 527 $num = count($events); | |
| 528 | |
| 529 ob_start(); | |
| 530 $return = $ical->export($events, null, true); | |
| 531 $output = ob_get_contents(); | |
| 532 ob_end_clean(); | |
| 533 | |
| 534 $this->assertTrue($return, "Return true on successful writing"); | |
| 535 $this->assertContains('BEGIN:VCALENDAR', $output, "VCALENDAR encapsulation BEGIN"); | |
| 536 $this->assertContains('END:VCALENDAR', $output, "VCALENDAR encapsulation END"); | |
| 537 $this->assertEquals($num, substr_count($output, 'BEGIN:VEVENT'), "VEVENT encapsulation BEGIN"); | |
| 538 $this->assertEquals($num, substr_count($output, 'END:VEVENT'), "VEVENT encapsulation END"); | |
| 539 } | |
| 540 | |
| 541 function test_datetime() | |
| 542 { | |
| 543 $ical = new libvcalendar(); | |
| 544 $cal = new \Sabre\VObject\Component\VCalendar(); | |
| 545 $localtime = $ical->datetime_prop($cal, 'DTSTART', new DateTime('2013-09-01 12:00:00', new DateTimeZone('Europe/Berlin'))); | |
| 546 $localdate = $ical->datetime_prop($cal, 'DTSTART', new DateTime('2013-09-01', new DateTimeZone('Europe/Berlin')), false, true); | |
| 547 $utctime = $ical->datetime_prop($cal, 'DTSTART', new DateTime('2013-09-01 12:00:00', new DateTimeZone('UTC'))); | |
| 548 $asutctime = $ical->datetime_prop($cal, 'DTSTART', new DateTime('2013-09-01 12:00:00', new DateTimeZone('Europe/Berlin')), true); | |
| 549 | |
| 550 $this->assertContains('TZID=Europe/Berlin', $localtime->serialize()); | |
| 551 $this->assertContains('VALUE=DATE', $localdate->serialize()); | |
| 552 $this->assertContains('20130901T120000Z', $utctime->serialize()); | |
| 553 $this->assertContains('20130901T100000Z', $asutctime->serialize()); | |
| 554 } | |
| 555 | |
| 556 function test_get_vtimezone() | |
| 557 { | |
| 558 $vtz = libvcalendar::get_vtimezone('Europe/Berlin', strtotime('2014-08-22T15:00:00+02:00')); | |
| 559 $this->assertInstanceOf('\Sabre\VObject\Component', $vtz, "VTIMEZONE is a Component object"); | |
| 560 $this->assertEquals('Europe/Berlin', $vtz->TZID); | |
| 561 $this->assertEquals('4', $vtz->{'X-MICROSOFT-CDO-TZID'}); | |
| 562 | |
| 563 // check for transition to daylight saving time which is BEFORE the given date | |
| 564 $dst = reset($vtz->select('DAYLIGHT')); | |
| 565 $this->assertEquals('DAYLIGHT', $dst->name); | |
| 566 $this->assertEquals('20140330T010000', $dst->DTSTART); | |
| 567 $this->assertEquals('+0100', $dst->TZOFFSETFROM); | |
| 568 $this->assertEquals('+0200', $dst->TZOFFSETTO); | |
| 569 $this->assertEquals('CEST', $dst->TZNAME); | |
| 570 | |
| 571 // check (last) transition to standard time which is AFTER the given date | |
| 572 $std = end($vtz->select('STANDARD')); | |
| 573 $this->assertEquals('STANDARD', $std->name); | |
| 574 $this->assertEquals('20141026T010000', $std->DTSTART); | |
| 575 $this->assertEquals('+0200', $std->TZOFFSETFROM); | |
| 576 $this->assertEquals('+0100', $std->TZOFFSETTO); | |
| 577 $this->assertEquals('CET', $std->TZNAME); | |
| 578 | |
| 579 // unknown timezone | |
| 580 $vtz = libvcalendar::get_vtimezone('America/Foo Bar'); | |
| 581 $this->assertEquals(false, $vtz); | |
| 582 | |
| 583 // invalid input data | |
| 584 $vtz = libvcalendar::get_vtimezone(new DateTime()); | |
| 585 $this->assertEquals(false, $vtz); | |
| 586 | |
| 587 // DateTimezone as input data | |
| 588 $vtz = libvcalendar::get_vtimezone(new DateTimezone('Pacific/Chatham')); | |
| 589 $this->assertInstanceOf('\Sabre\VObject\Component', $vtz); | |
| 590 $this->assertContains('TZOFFSETFROM:+1245', $vtz->serialize()); | |
| 591 $this->assertContains('TZOFFSETTO:+1345', $vtz->serialize()); | |
| 592 } | |
| 593 | |
| 594 function get_attachment_data($id, $event) | |
| 595 { | |
| 596 return $this->attachment_data; | |
| 597 } | |
| 598 } | |
| 599 |
