4
|
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
|