1<?php
2/**
3 * @category   Horde
4 * @package    Icalendar
5 * @subpackage UnitTests
6 */
7
8/**
9 * @category   Horde
10 * @package    Icalendar
11 * @subpackage UnitTests
12 */
13class Horde_Icalendar_ExportTest extends Horde_Test_Case
14{
15    public function testLineFolding()
16    {
17        $ical = new Horde_Icalendar();
18        $event = Horde_Icalendar::newComponent('vevent', $ical);
19        $event->setAttribute('UID', 'XXX');
20        $event->setAttribute('DTSTART', array('year' => 2008, 'month' => 1, 'mday' => 1), array('VALUE' => 'DATE'));
21        $event->setAttribute('DTSTAMP', array('year' => 2008, 'month' => 1, 'mday' => 1), array('VALUE' => 'DATE'));
22        $event->setAttribute('DESCRIPTION', 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam sollicitudin faucibus mauris amet.');
23        $event->setAttribute('BINARY', base64_encode('Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam sollicitudin faucibus mauris amet.'), array('ENCODING' => 'b'));
24        $ical->addComponent($event);
25        $this->assertStringEqualsFile(
26            __DIR__ . '/fixtures/line-folding-1.ics',
27            $ical->exportVCalendar()
28        );
29
30        $ical = new Horde_Icalendar('1.0');
31        $event = Horde_Icalendar::newComponent('vevent', $ical);
32        $event->setAttribute('UID', 'XXX');
33        $event->setAttribute('DTSTART', array('year' => 2008, 'month' => 1, 'mday' => 1), array('VALUE' => 'DATE'));
34        $event->setAttribute('DTSTAMP', array('year' => 2008, 'month' => 1, 'mday' => 1), array('VALUE' => 'DATE'));
35        $event->setAttribute('DESCRIPTION', 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam sollicitudin faucibus mauris amet.');
36        $ical->addComponent($event);
37        $this->assertStringEqualsFile(
38            __DIR__ . '/fixtures/line-folding-2.ics',
39            $ical->exportVCalendar()
40        );
41
42        $ical = new Horde_Icalendar();
43        $event = Horde_Icalendar::newComponent('vevent', $ical);
44        $event->setAttribute('UID', 'XXX');
45        $event->setAttribute('DTSTART', array('year' => 2008, 'month' => 1, 'mday' => 1), array('VALUE' => 'DATE'));
46        $event->setAttribute('DTSTAMP', array('year' => 2008, 'month' => 1, 'mday' => 1), array('VALUE' => 'DATE'));
47        $event->setAttribute('DESCRIPTION', 'Lörem ipsüm dölör sit ämet, cönsectetüer ädipiscing elit. Aliqüäm söllicitüdin fäücibüs mäüris ämet.');
48        $ical->addComponent($event);
49        $this->assertStringEqualsFile(
50            __DIR__ . '/fixtures/line-folding-3.ics',
51            $ical->exportVCalendar()
52        );
53
54        $ical = new Horde_Icalendar('1.0');
55        $event = Horde_Icalendar::newComponent('vevent', $ical);
56        $event->setAttribute('UID', 'XXX');
57        $event->setAttribute('DTSTART', array('year' => 2008, 'month' => 1, 'mday' => 1), array('VALUE' => 'DATE'));
58        $event->setAttribute('DTSTAMP', array('year' => 2008, 'month' => 1, 'mday' => 1), array('VALUE' => 'DATE'));
59        $event->setAttribute('DESCRIPTION', 'Lörem ipsüm dölör sit ämet, cönsectetüer ädipiscing elit. Aliqüäm söllicitüdin fäücibüs mäüris ämet.', array('CHARSET' => 'UTF-8'));
60        $ical->addComponent($event);
61        $this->assertStringEqualsFile(
62            __DIR__ . '/fixtures/line-folding-4.ics',
63            $ical->exportVCalendar()
64        );
65
66        $ical = new Horde_Icalendar('1.0');
67        $event = Horde_Icalendar::newComponent('vevent', $ical);
68        $event->setAttribute('UID', 'XXX');
69        $event->setAttribute('DTSTART', array('year' => 2008, 'month' => 1, 'mday' => 1), array('VALUE' => 'DATE'));
70        $event->setAttribute('DTSTAMP', array('year' => 2008, 'month' => 1, 'mday' => 1), array('VALUE' => 'DATE'));
71        $event->setAttribute('DESCRIPTION', 'Löremipsümdölörsitämet,cönsectetüerädipiscingelit.Aliqüämsöllicitüdinfäücibüsmäürisämet. Löremipsümdölörsitämet,cönsectetüerädipiscingelit.Aliqüämsöllicitüdinfäücibüsmäürisämet.', array('CHARSET' => 'UTF-8'));
72        $ical->addComponent($event);
73        $this->assertStringEqualsFile(
74            __DIR__ . '/fixtures/line-folding-5.ics',
75            $ical->exportVCalendar()
76        );
77
78        $ical = new Horde_Icalendar();
79        $event = Horde_Icalendar::newComponent('vevent', $ical);
80        $event->setAttribute('UID', 'XXX');
81        $event->setAttribute('DTSTART', array('year' => 2008, 'month' => 1, 'mday' => 1), array('VALUE' => 'DATE'));
82        $event->setAttribute('DTSTAMP', array('year' => 2008, 'month' => 1, 'mday' => 1), array('VALUE' => 'DATE'));
83        $description = <<<EOT
84SYLVIE DAGORNE a écrit :
85
86Bonjour,
87
88suite à mon appel téléphonique auprès de Jacques Benzerara, il m'a renvoyé vers vous. En effet, je souhaiterais vous rencontrer car:
891°) au niveau de l'observatoire local nous devons lancer une enquête sur un suivi de cohorte à la rentrée prochaine qui concernera tous les étudiants de L1. Nous souhaiterons faire un questionnaire en ligne ce questionnaire devra être hébergé sur un serveur.
90
912°) dans le cadre de l'observatoire régional, nos partenaires nous demande également de faire des questionnaires en ligne. Nous disposons du logiciel Modalisa qui permet de le réaliser mais du point de vu technique, nous avons besoin de voir avec vous,  les difficultés et les limites d'un tel dispositif afin de voir les démarches à suivre et pouvoir évoquer tous ces problèmes techniques, je souhaiterais vous rencontrer. Merci de me précisez vos disponibilités?
92...
93Je serai accompagné d'un collègue pour l'observatoire local (David Le foll) et de la chargée d'études de l'observatoire régional (Amélie Gicquel) pour la partie régionale.
94EOT;
95        $event->setAttribute('DESCRIPTION', $description);
96        $ical->addComponent($event);
97        $this->assertStringEqualsFile(
98            __DIR__ . '/fixtures/line-folding-6.ics',
99            $ical->exportVCalendar()
100        );
101    }
102
103    public function testEscapes()
104    {
105        $ical = new Horde_Icalendar();
106
107        $event1 = Horde_Icalendar::newComponent('vevent', $ical);
108        $event2 = Horde_Icalendar::newComponent('vevent', $ical);
109
110        $event1->setAttribute('UID', '20041120-8550-innerjoin-org');
111        $event1->setAttribute('DTSTART', array('year' => 2005, 'month' => 5, 'mday' => 3), array('VALUE' => 'DATE'));
112        $event1->setAttribute('DTSTAMP', array('year' => 2004, 'month' => 11, 'mday' => 20), array('VALUE' => 'DATE'));
113        $event1->setAttribute('SUMMARY', 'Escaped Comma in Description Field');
114        $event1->setAttribute('DESCRIPTION', 'There is a comma (escaped with a baskslash) in this sentence and some important words after it, see anything here?');
115        $event1->setAttribute('CATEGORIES', null, array(), true, array('Foo'));
116
117        $event2->setAttribute('UID', '20041120-8549-innerjoin-org');
118        $event2->setAttribute('DTSTART', array('year' => 2005, 'month' => 5, 'mday' => 4), array('VALUE' => 'DATE'));
119        $event2->setAttribute('DTSTAMP', array('year' => 2004, 'month' => 11, 'mday' => 20), array('VALUE' => 'DATE'));
120        $event2->setAttribute('SUMMARY', 'Dash (rather than Comma) in the Description Field');
121        $event2->setAttribute('DESCRIPTION', 'There are important words after this dash - see anything here or have the words gone?');
122        $event2->setAttribute('CATEGORIES', null, array(), true, array('Foo', 'Foo,Bar', 'Bar'));
123
124        $ical->addComponent($event1);
125        $ical->addComponent($event2);
126
127        $this->assertStringEqualsFile(
128            __DIR__ . '/fixtures/escapes2.ics',
129            $ical->exportVCalendar()
130        );
131
132        $readIcal = new Horde_Icalendar();
133        $readIcal->parseVCalendar($ical->exportVCalendar());
134        $this->assertEquals(
135            array('There is a comma (escaped with a baskslash) in this sentence and some important words after it, see anything here?'),
136            $readIcal->getComponent(0)->getAttributeValues('DESCRIPTION')
137        );
138        $this->assertEquals(
139            array('There are important words after this dash - see anything here or have the words gone?'),
140            $readIcal->getComponent(1)->getAttributeValues('DESCRIPTION')
141        );
142
143        foreach (array('2.1', '3.0') as $version) {
144            $contact = new Horde_Icalendar_Vcard($version);
145            $contact->setAttribute(
146                'N', null, array(), true, array('Contact', 'Test')
147            );
148            $contact->setAttribute('FN', 'Test,Contact');
149            $contact->setAttribute(
150                'ORG', null, array(), true, array('My,Company', 'IT Department')
151            );
152            $this->assertStringEqualsFile(
153                __DIR__ . '/fixtures/vcard' . $version . '.vcs',
154                $contact->exportVcalendar()
155            );
156            $readIcal = new Horde_Icalendar();
157            $readIcal->parseVCalendar($contact->exportVCalendar());
158            $vcard = $readIcal->getComponent(0);
159            $this->assertEquals(
160                array('Contact', 'Test'), $vcard->getAttributeValues('N')
161            );
162            $this->assertEquals(
163                array('Test,Contact'), $vcard->getAttributeValues('FN')
164            );
165            $this->assertEquals(
166                array('My,Company', 'IT Department'),
167                $vcard->getAttributeValues('ORG')
168            );
169        }
170    }
171
172    public function testQuotedParameters()
173    {
174        $ical = new Horde_Icalendar();
175        $event1 = Horde_Icalendar::newComponent('vevent', $ical);
176        $event1->setAttribute('UID', '20041120-8550-innerjoin-org');
177        $event1->setAttribute('DTSTART', array('year' => 2005, 'month' => 5, 'mday' => 3), array('VALUE' => 'DATE'));
178        $event1->setAttribute('DTSTAMP', array('year' => 2004, 'month' => 11, 'mday' => 20), array('VALUE' => 'DATE'));
179        $event1->setAttribute('SUMMARY', 'Escaped Comma in Description Field');
180        $event1->setAttribute('DESCRIPTION', 'There is a comma (escaped with a baskslash) in this sentence and some important words after it, see anything here?');
181        $event1->setAttribute('ORGANIZER', 'mailto:mueller@example.org', array('CN' => "Klä,rc\"hen;\n Mül:ler"));
182        $ical->addComponent($event1);
183        $this->assertStringEqualsFile(
184            __DIR__ . '/fixtures/quoted-params.ics',
185            $ical->exportVCalendar()
186        );
187    }
188
189    public function testTimezone()
190    {
191        $date = new Horde_Date(
192            array(
193                'year' => 2010,
194                'month' => 1,
195                'mday' => 1,
196                'hour' => 1,
197                'min' => 0,
198                'sec' => 0,
199            ),
200            'UTC'
201        );
202        $ical = new Horde_Icalendar();
203        $event = Horde_Icalendar::newComponent('vevent', $ical);
204        $event->setAttribute('UID', 'uid');
205        $event->setAttribute('DTSTAMP', $date);
206        $event->setAttribute('DTSTART', $date);
207        $ical->addComponent($event);
208        $this->assertStringEqualsFile(
209            __DIR__ . '/fixtures/timezone1.ics',
210            $ical->exportVCalendar()
211        );
212
213        $ical = new Horde_Icalendar();
214        $event = Horde_Icalendar::newComponent('vevent', $ical);
215        $event->setAttribute('UID', 'uid');
216        $event->setAttribute('DTSTAMP', $date);
217        $date->setTimezone('Europe/Berlin');
218        $event->setAttribute('DTSTART', $date, array('TZID' => 'Europe/Berlin'));
219        $ical->addComponent($event);
220        $this->assertStringEqualsFile(
221            __DIR__ . '/fixtures/timezone2.ics',
222            $ical->exportVCalendar()
223        );
224
225        $ical = new Horde_Icalendar();
226        $tz = $ical->parsevCalendar(
227            file_get_contents(__DIR__ . '/fixtures/timezone3.ics')
228        );
229        $tz = $ical->getComponent(0);
230        $ical = new Horde_Icalendar();
231        $ical->addComponent($tz);
232        $event = Horde_Icalendar::newComponent('vevent', $ical);
233        $event->setAttribute('UID', 'uid');
234        $event->setAttribute('DTSTAMP', $date);
235        $date->setTimezone('Europe/Berlin');
236        $event->setAttribute('DTSTART', $date, array('TZID' => 'Europe/Berlin'));
237        $ical->addComponent($event);
238        $ical->addComponent($tz);
239        $event = Horde_Icalendar::newComponent('vevent', $ical);
240        $event->setAttribute('UID', 'uid2');
241        $event->setAttribute('DTSTAMP', $date);
242        $date->setTimezone('Europe/Berlin');
243        $start = clone $date;
244        $start->mday++;
245        $event->setAttribute('DTSTART', $start, array('TZID' => 'Europe/Berlin'));
246        $ical->addComponent($event);
247        $this->assertStringEqualsFile(
248            __DIR__ . '/fixtures/timezone4.ics',
249            $ical->exportVCalendar()
250        );
251    }
252
253    public function testSingleCategoriesV1()
254    {
255        $date = new Horde_Date(
256            array(
257                'year' => 2010,
258                'month' => 1,
259                'mday' => 1,
260                'hour' => 1,
261                'min' => 0,
262                'sec' => 0,
263            ),
264            'UTC'
265        );
266        $ical = new Horde_Icalendar('1.0');
267        $vEvent = Horde_Icalendar::newComponent('VEVENT', $ical);
268        $vEvent->setAttribute('UID', '5b3be1a5-d1b0-43c1-bad4-6c29eebab01e');
269        $vEvent->setAttribute('CATEGORIES', null, array(), true, array('Foo'));
270        $vEvent->setAttribute('DTSTART', $date);
271        $ical->addComponent($vEvent);
272
273        $this->assertStringEqualsFile(
274            __DIR__ . '/fixtures/single-categoryv1.ics',
275            $this->_removeDateStamp($ical->exportVCalendar())
276        );
277    }
278
279    public function testMultipleCategoriesV1()
280    {
281        $date = new Horde_Date(
282            array(
283                'year' => 2010,
284                'month' => 1,
285                'mday' => 1,
286                'hour' => 1,
287                'min' => 0,
288                'sec' => 0,
289            ),
290            'UTC'
291        );
292        $ical = new Horde_Icalendar('1.0');
293        $vEvent = Horde_Icalendar::newComponent('VEVENT', $ical);
294        $vEvent->setAttribute('UID', '5b3be1a5-d1b0-43c1-bad4-6c29eebab01e');
295        $vEvent->setAttribute('CATEGORIES', null, array(), true, array('Foo', 'Bar'));
296        $vEvent->setAttribute('DTSTART', $date);
297        $ical->addComponent($vEvent);
298
299        $this->assertStringEqualsFile(
300            __DIR__ . '/fixtures/multiple-categoryv1.ics',
301            $this->_removeDateStamp($ical->exportVCalendar())
302        );
303    }
304
305    public function testDuration0()
306    {
307        $ical = new Horde_Icalendar;
308        $vevent = Horde_Icalendar::newComponent('VEVENT', $ical);
309        $vevent->setAttribute('SUMMARY', 'Testevent');
310        $vevent->setAttribute('UID', 'XXX');
311        $vevent->setAttribute('DTSTART', array('year' => 2015, 'month' => 7, 'mday' => 1), array('VALUE' => 'DATE'));
312        $vevent->setAttribute('DTSTAMP', array('year' => 2015, 'month' => 7, 'mday' => 1), array('VALUE' => 'DATE'));
313        $vevent->setAttribute('DURATION', 0);
314        $ical->addComponent($vevent);
315        $valarm = Horde_Icalendar::newComponent('VALARM', $vevent);
316        $valarm->setAttribute('TRIGGER', 0, array(
317            'VALUE' => 'DURATION',
318            'RELATED' => 'START',
319        ));
320        $valarm->setAttribute('DESCRIPTION', 'Alarm at event-start');
321        $vevent->addComponent($valarm);
322        $this->assertStringEqualsFile(
323            __DIR__ . '/fixtures/duration0.ics',
324            $ical->exportVCalendar()
325        );
326    }
327
328    public function testDuration8d_not_1w1d()
329    {
330        $ical = new Horde_Icalendar;
331        $vevent = Horde_Icalendar::newComponent('VEVENT', $ical);
332        $vevent->setAttribute('SUMMARY', 'Testevent 8 days long');
333        $vevent->setAttribute('UID', 'XXX');
334        $vevent->setAttribute('DTSTART', array('year' => 2015, 'month' => 7, 'mday' => 1), array('VALUE' => 'DATE'));
335        $vevent->setAttribute('DTSTAMP', array('year' => 2015, 'month' => 7, 'mday' => 1), array('VALUE' => 'DATE'));
336        $vevent->setAttribute('DURATION', 8 * 86400);
337        $ical->addComponent($vevent);
338        $valarm = Horde_Icalendar::newComponent('VALARM', $vevent);
339        $valarm->setAttribute('TRIGGER', -7 * 86400, array(
340            'VALUE' => 'DURATION',
341            'RELATED' => 'START',
342        ));
343        $valarm->setAttribute('DESCRIPTION', 'Alarm one week before');
344        $vevent->addComponent($valarm);
345        $this->assertStringEqualsFile(
346            __DIR__ . '/fixtures/duration8d.ics',
347            $ical->exportVCalendar()
348        );
349    }
350
351        private function _removeDateStamp($ics)
352    {
353        return preg_replace(
354            '/DTSTAMP:\d\d\d\d\d\d\d\dT\d\d\d\d\d\dZ/',
355            'DTSTAMP:--------T------Z',
356            $ics
357        );
358    }
359}
360