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 |