1<?php
2
3namespace Sabre\VObject\Parser;
4
5use Sabre\VObject;
6
7class XmlTest extends \PHPUnit_Framework_TestCase {
8
9    use VObject\PHPUnitAssertions;
10
11    function testRFC6321Example1() {
12
13        $this->assertXMLEqualsToMimeDir(
14<<<XML
15<?xml version="1.0" encoding="UTF-8"?>
16<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0">
17 <vcalendar>
18  <properties>
19   <calscale>
20     <text>GREGORIAN</text>
21   </calscale>
22   <prodid>
23    <text>-//Example Inc.//Example Calendar//EN</text>
24   </prodid>
25   <version>
26     <text>2.0</text>
27   </version>
28  </properties>
29  <components>
30   <vevent>
31    <properties>
32     <dtstamp>
33       <date-time>2008-02-05T19:12:24Z</date-time>
34     </dtstamp>
35     <dtstart>
36       <date>2008-10-06</date>
37     </dtstart>
38     <summary>
39      <text>Planning meeting</text>
40     </summary>
41     <uid>
42      <text>4088E990AD89CB3DBB484909</text>
43     </uid>
44    </properties>
45   </vevent>
46  </components>
47 </vcalendar>
48</icalendar>
49XML
50,
51            'BEGIN:VCALENDAR' . "\n" .
52            // VERSION comes first because this is required by vCard 4.0.
53            'VERSION:2.0' . "\n" .
54            'CALSCALE:GREGORIAN' . "\n" .
55            'PRODID:-//Example Inc.//Example Calendar//EN' . "\n" .
56            'BEGIN:VEVENT' . "\n" .
57            'DTSTAMP:20080205T191224Z' . "\n" .
58            'DTSTART;VALUE=DATE:20081006' . "\n" .
59            'SUMMARY:Planning meeting' . "\n" .
60            'UID:4088E990AD89CB3DBB484909' . "\n" .
61            'END:VEVENT' . "\n" .
62            'END:VCALENDAR' . "\n"
63        );
64
65    }
66
67    function testRFC6321Example2() {
68
69        $xml = <<<XML
70<?xml version="1.0" encoding="UTF-8" ?>
71<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0">
72  <vcalendar>
73    <properties>
74      <prodid>
75        <text>-//Example Inc.//Example Client//EN</text>
76      </prodid>
77      <version>
78        <text>2.0</text>
79      </version>
80    </properties>
81    <components>
82      <vtimezone>
83        <properties>
84          <last-modified>
85            <date-time>2004-01-10T03:28:45Z</date-time>
86          </last-modified>
87          <tzid><text>US/Eastern</text></tzid>
88        </properties>
89        <components>
90          <daylight>
91            <properties>
92              <dtstart>
93                <date-time>2000-04-04T02:00:00</date-time>
94              </dtstart>
95              <rrule>
96                <recur>
97                  <freq>YEARLY</freq>
98                  <byday>1SU</byday>
99                  <bymonth>4</bymonth>
100                </recur>
101              </rrule>
102              <tzname>
103                <text>EDT</text>
104              </tzname>
105              <tzoffsetfrom>
106                <utc-offset>-05:00</utc-offset>
107              </tzoffsetfrom>
108              <tzoffsetto>
109                <utc-offset>-04:00</utc-offset>
110              </tzoffsetto>
111            </properties>
112          </daylight>
113          <standard>
114            <properties>
115              <dtstart>
116                <date-time>2000-10-26T02:00:00</date-time>
117              </dtstart>
118              <rrule>
119                <recur>
120                  <freq>YEARLY</freq>
121                  <byday>-1SU</byday>
122                  <bymonth>10</bymonth>
123                </recur>
124              </rrule>
125              <tzname>
126                <text>EST</text>
127              </tzname>
128              <tzoffsetfrom>
129                <utc-offset>-04:00</utc-offset>
130              </tzoffsetfrom>
131              <tzoffsetto>
132                <utc-offset>-05:00</utc-offset>
133              </tzoffsetto>
134            </properties>
135          </standard>
136        </components>
137      </vtimezone>
138      <vevent>
139        <properties>
140          <dtstamp>
141            <date-time>2006-02-06T00:11:21Z</date-time>
142          </dtstamp>
143          <dtstart>
144            <parameters>
145              <tzid><text>US/Eastern</text></tzid>
146            </parameters>
147            <date-time>2006-01-02T12:00:00</date-time>
148          </dtstart>
149          <duration>
150            <duration>PT1H</duration>
151          </duration>
152          <rrule>
153            <recur>
154              <freq>DAILY</freq>
155              <count>5</count>
156            </recur>
157          </rrule>
158          <rdate>
159            <parameters>
160              <tzid><text>US/Eastern</text></tzid>
161            </parameters>
162            <period>
163              <start>2006-01-02T15:00:00</start>
164              <duration>PT2H</duration>
165            </period>
166          </rdate>
167          <summary>
168            <text>Event #2</text>
169          </summary>
170          <description>
171            <text>We are having a meeting all this week at 12
172pm for one hour, with an additional meeting on the first day
1732 hours long.&#x0a;Please bring your own lunch for the 12 pm
174meetings.</text>
175          </description>
176          <uid>
177            <text>00959BC664CA650E933C892C@example.com</text>
178          </uid>
179        </properties>
180      </vevent>
181      <vevent>
182        <properties>
183          <dtstamp>
184            <date-time>2006-02-06T00:11:21Z</date-time>
185          </dtstamp>
186          <dtstart>
187            <parameters>
188              <tzid><text>US/Eastern</text></tzid>
189            </parameters>
190            <date-time>2006-01-04T14:00:00</date-time>
191          </dtstart>
192          <duration>
193            <duration>PT1H</duration>
194          </duration>
195          <recurrence-id>
196            <parameters>
197              <tzid><text>US/Eastern</text></tzid>
198            </parameters>
199            <date-time>2006-01-04T12:00:00</date-time>
200          </recurrence-id>
201          <summary>
202            <text>Event #2 bis</text>
203          </summary>
204          <uid>
205            <text>00959BC664CA650E933C892C@example.com</text>
206          </uid>
207        </properties>
208      </vevent>
209    </components>
210  </vcalendar>
211</icalendar>
212XML;
213
214        $component = VObject\Reader::readXML($xml);
215        $this->assertVObjectEqualsVObject(
216            'BEGIN:VCALENDAR' . "\n" .
217            'VERSION:2.0' . "\n" .
218            'PRODID:-//Example Inc.//Example Client//EN' . "\n" .
219            'BEGIN:VTIMEZONE' . "\n" .
220            'LAST-MODIFIED:20040110T032845Z' . "\n" .
221            'TZID:US/Eastern' . "\n" .
222            'BEGIN:DAYLIGHT' . "\n" .
223            'DTSTART:20000404T020000' . "\n" .
224            'RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4' . "\n" .
225            'TZNAME:EDT' . "\n" .
226            'TZOFFSETFROM:-0500' . "\n" .
227            'TZOFFSETTO:-0400' . "\n" .
228            'END:DAYLIGHT' . "\n" .
229            'BEGIN:STANDARD' . "\n" .
230            'DTSTART:20001026T020000' . "\n" .
231            'RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10' . "\n" .
232            'TZNAME:EST' . "\n" .
233            'TZOFFSETFROM:-0400' . "\n" .
234            'TZOFFSETTO:-0500' . "\n" .
235            'END:STANDARD' . "\n" .
236            'END:VTIMEZONE' . "\n" .
237            'BEGIN:VEVENT' . "\n" .
238            'DTSTAMP:20060206T001121Z' . "\n" .
239            'DTSTART;TZID=US/Eastern:20060102T120000' . "\n" .
240            'DURATION:PT1H' . "\n" .
241            'RRULE:FREQ=DAILY;COUNT=5' . "\n" .
242            'RDATE;TZID=US/Eastern;VALUE=PERIOD:20060102T150000/PT2H' . "\n" .
243            'SUMMARY:Event #2' . "\n" .
244            'DESCRIPTION:We are having a meeting all this week at 12\npm for one hour\, ' . "\n" .
245            ' with an additional meeting on the first day\n2 hours long.\nPlease bring y' . "\n" .
246            ' our own lunch for the 12 pm\nmeetings.' . "\n" .
247            'UID:00959BC664CA650E933C892C@example.com' . "\n" .
248            'END:VEVENT' . "\n" .
249            'BEGIN:VEVENT' . "\n" .
250            'DTSTAMP:20060206T001121Z' . "\n" .
251            'DTSTART;TZID=US/Eastern:20060104T140000' . "\n" .
252            'DURATION:PT1H' . "\n" .
253            'RECURRENCE-ID;TZID=US/Eastern:20060104T120000' . "\n" .
254            'SUMMARY:Event #2 bis' . "\n" .
255            'UID:00959BC664CA650E933C892C@example.com' . "\n" .
256            'END:VEVENT' . "\n" .
257            'END:VCALENDAR' . "\n",
258            VObject\Writer::write($component)
259        );
260
261    }
262
263    /**
264     * iCalendar Stream.
265     */
266    function testRFC6321Section3_2() {
267
268        $this->assertXMLReflexivelyEqualsToMimeDir(
269<<<XML
270<?xml version="1.0" encoding="UTF-8"?>
271<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0">
272 <vcalendar/>
273</icalendar>
274XML
275,
276            'BEGIN:VCALENDAR' . "\n" .
277            'END:VCALENDAR' . "\n"
278        );
279    }
280
281    /**
282     * All components exist.
283     */
284    function testRFC6321Section3_3() {
285
286        $this->assertXMLReflexivelyEqualsToMimeDir(
287<<<XML
288<?xml version="1.0" encoding="UTF-8"?>
289<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0">
290 <vcalendar>
291  <components>
292   <vtimezone/>
293   <vevent/>
294   <vtodo/>
295   <vjournal/>
296   <vfreebusy/>
297   <standard/>
298   <daylight/>
299   <valarm/>
300  </components>
301 </vcalendar>
302</icalendar>
303XML
304,
305            'BEGIN:VCALENDAR' . "\n" .
306            'BEGIN:VTIMEZONE' . "\n" .
307            'END:VTIMEZONE' . "\n" .
308            'BEGIN:VEVENT' . "\n" .
309            'END:VEVENT' . "\n" .
310            'BEGIN:VTODO' . "\n" .
311            'END:VTODO' . "\n" .
312            'BEGIN:VJOURNAL' . "\n" .
313            'END:VJOURNAL' . "\n" .
314            'BEGIN:VFREEBUSY' . "\n" .
315            'END:VFREEBUSY' . "\n" .
316            'BEGIN:STANDARD' . "\n" .
317            'END:STANDARD' . "\n" .
318            'BEGIN:DAYLIGHT' . "\n" .
319            'END:DAYLIGHT' . "\n" .
320            'BEGIN:VALARM' . "\n" .
321            'END:VALARM' . "\n" .
322            'END:VCALENDAR' . "\n"
323        );
324
325    }
326
327    /**
328     * Properties, Special Cases, GEO.
329     */
330    function testRFC6321Section3_4_1_2() {
331
332        $this->assertXMLReflexivelyEqualsToMimeDir(
333<<<XML
334<?xml version="1.0" encoding="UTF-8"?>
335<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0">
336 <vcalendar>
337  <properties>
338   <geo>
339    <latitude>37.386013</latitude>
340    <longitude>-122.082932</longitude>
341   </geo>
342  </properties>
343 </vcalendar>
344</icalendar>
345XML
346,
347            'BEGIN:VCALENDAR' . "\n" .
348            'GEO:37.386013;-122.082932' . "\n" .
349            'END:VCALENDAR' . "\n"
350        );
351
352    }
353
354    /**
355     * Properties, Special Cases, REQUEST-STATUS.
356     */
357    function testRFC6321Section3_4_1_3() {
358
359        // Example 1 of RFC5545, Section 3.8.8.3.
360        $this->assertXMLReflexivelyEqualsToMimeDir(
361<<<XML
362<?xml version="1.0" encoding="UTF-8"?>
363<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0">
364 <vcalendar>
365  <properties>
366   <request-status>
367    <code>2.0</code>
368    <description>Success</description>
369   </request-status>
370  </properties>
371 </vcalendar>
372</icalendar>
373XML
374,
375            'BEGIN:VCALENDAR' . "\n" .
376            'REQUEST-STATUS:2.0;Success' . "\n" .
377            'END:VCALENDAR' . "\n"
378        );
379
380        // Example 2 of RFC5545, Section 3.8.8.3.
381        $this->assertXMLReflexivelyEqualsToMimeDir(
382<<<XML
383<?xml version="1.0" encoding="UTF-8"?>
384<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0">
385 <vcalendar>
386  <properties>
387   <request-status>
388    <code>3.1</code>
389    <description>Invalid property value</description>
390    <data>DTSTART:96-Apr-01</data>
391   </request-status>
392  </properties>
393 </vcalendar>
394</icalendar>
395XML
396,
397            'BEGIN:VCALENDAR' . "\n" .
398            'REQUEST-STATUS:3.1;Invalid property value;DTSTART:96-Apr-01' . "\n" .
399            'END:VCALENDAR' . "\n"
400        );
401
402        // Example 3 of RFC5545, Section 3.8.8.3.
403        $this->assertXMLReflexivelyEqualsToMimeDir(
404<<<XML
405<?xml version="1.0" encoding="UTF-8"?>
406<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0">
407 <vcalendar>
408  <properties>
409   <request-status>
410    <code>2.8</code>
411    <description>Success, repeating event ignored. Scheduled as a single event.</description>
412    <data>RRULE:FREQ=WEEKLY;INTERVAL=2</data>
413   </request-status>
414  </properties>
415 </vcalendar>
416</icalendar>
417XML
418,
419            'BEGIN:VCALENDAR' . "\n" .
420            'REQUEST-STATUS:2.8;Success\, repeating event ignored. Scheduled as a single' . "\n" .
421            '  event.;RRULE:FREQ=WEEKLY\;INTERVAL=2' . "\n" .
422            'END:VCALENDAR' . "\n"
423        );
424
425        // Example 4 of RFC5545, Section 3.8.8.3.
426        $this->assertXMLReflexivelyEqualsToMimeDir(
427<<<XML
428<?xml version="1.0" encoding="UTF-8"?>
429<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0">
430 <vcalendar>
431  <properties>
432   <request-status>
433    <code>4.1</code>
434    <description>Event conflict.  Date-time is busy.</description>
435   </request-status>
436  </properties>
437 </vcalendar>
438</icalendar>
439XML
440,
441            'BEGIN:VCALENDAR' . "\n" .
442            'REQUEST-STATUS:4.1;Event conflict.  Date-time is busy.' . "\n" .
443            'END:VCALENDAR' . "\n"
444        );
445
446        // Example 5 of RFC5545, Section 3.8.8.3.
447        $this->assertXMLReflexivelyEqualsToMimeDir(
448<<<XML
449<?xml version="1.0" encoding="UTF-8"?>
450<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0">
451 <vcalendar>
452  <properties>
453   <request-status>
454    <code>3.7</code>
455    <description>Invalid calendar user</description>
456    <data>ATTENDEE:mailto:jsmith@example.com</data>
457   </request-status>
458  </properties>
459 </vcalendar>
460</icalendar>
461XML
462,
463            'BEGIN:VCALENDAR' . "\n" .
464            'REQUEST-STATUS:3.7;Invalid calendar user;ATTENDEE:mailto:jsmith@example.com' . "\n" .
465            'END:VCALENDAR' . "\n"
466        );
467
468    }
469
470    /**
471     * Values, Binary.
472     */
473    function testRFC6321Section3_6_1() {
474
475        $this->assertXMLEqualsToMimeDir(
476<<<XML
477<?xml version="1.0" encoding="UTF-8"?>
478<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0">
479 <vcalendar>
480  <properties>
481   <attach>
482    <binary>SGVsbG8gV29ybGQh</binary>
483   </attach>
484  </properties>
485 </vcalendar>
486</icalendar>
487XML
488,
489            'BEGIN:VCALENDAR' . "\n" .
490            'ATTACH:SGVsbG8gV29ybGQh' . "\n" .
491            'END:VCALENDAR' . "\n"
492        );
493
494        // In vCard 4, BINARY no longer exists and is replaced by URI.
495        $this->assertXMLReflexivelyEqualsToMimeDir(
496<<<XML
497<?xml version="1.0" encoding="UTF-8"?>
498<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0">
499 <vcalendar>
500  <properties>
501   <attach>
502    <uri>SGVsbG8gV29ybGQh</uri>
503   </attach>
504  </properties>
505 </vcalendar>
506</icalendar>
507XML
508,
509            'BEGIN:VCALENDAR' . "\n" .
510            'ATTACH:SGVsbG8gV29ybGQh' . "\n" .
511            'END:VCALENDAR' . "\n"
512        );
513
514    }
515
516    /**
517     * Values, Boolean.
518     */
519    function testRFC6321Section3_6_2() {
520
521        $this->assertXMLEqualsToMimeDir(
522<<<XML
523<?xml version="1.0" encoding="UTF-8"?>
524<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0">
525 <vcalendar>
526  <properties>
527   <attendee>
528    <parameters>
529     <rsvp><boolean>true</boolean></rsvp>
530    </parameters>
531    <cal-address>mailto:cyrus@example.com</cal-address>
532   </attendee>
533  </properties>
534 </vcalendar>
535</icalendar>
536XML
537,
538            'BEGIN:VCALENDAR' . "\n" .
539            'ATTENDEE;RSVP=true:mailto:cyrus@example.com' . "\n" .
540            'END:VCALENDAR' . "\n"
541        );
542
543    }
544
545    /**
546     * Values, Calendar User Address.
547     */
548    function testRFC6321Section3_6_3() {
549
550        $this->assertXMLReflexivelyEqualsToMimeDir(
551<<<XML
552<?xml version="1.0" encoding="UTF-8"?>
553<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0">
554 <vcalendar>
555  <properties>
556   <attendee>
557    <cal-address>mailto:cyrus@example.com</cal-address>
558   </attendee>
559  </properties>
560 </vcalendar>
561</icalendar>
562XML
563,
564            'BEGIN:VCALENDAR' . "\n" .
565            'ATTENDEE:mailto:cyrus@example.com' . "\n" .
566            'END:VCALENDAR' . "\n"
567        );
568
569    }
570
571    /**
572     * Values, Date.
573     */
574    function testRFC6321Section3_6_4() {
575
576        $this->assertXMLReflexivelyEqualsToMimeDir(
577<<<XML
578<?xml version="1.0" encoding="UTF-8"?>
579<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0">
580 <vcalendar>
581  <properties>
582   <dtstart>
583    <date>2011-05-17</date>
584   </dtstart>
585  </properties>
586 </vcalendar>
587</icalendar>
588XML
589,
590            'BEGIN:VCALENDAR' . "\n" .
591            'DTSTART;VALUE=DATE:20110517' . "\n" .
592            'END:VCALENDAR' . "\n"
593        );
594
595    }
596
597    /**
598     * Values, Date-Time.
599     */
600    function testRFC6321Section3_6_5() {
601
602        $this->assertXMLReflexivelyEqualsToMimeDir(
603<<<XML
604<?xml version="1.0" encoding="UTF-8"?>
605<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0">
606 <vcalendar>
607  <properties>
608   <dtstart>
609    <date-time>2011-05-17T12:00:00</date-time>
610   </dtstart>
611  </properties>
612 </vcalendar>
613</icalendar>
614XML
615,
616            'BEGIN:VCALENDAR' . "\n" .
617            'DTSTART:20110517T120000' . "\n" .
618            'END:VCALENDAR' . "\n"
619        );
620
621    }
622
623    /**
624     * Values, Duration.
625     */
626    function testRFC6321Section3_6_6() {
627
628        $this->assertXMLReflexivelyEqualsToMimeDir(
629<<<XML
630<?xml version="1.0" encoding="UTF-8"?>
631<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0">
632 <vcalendar>
633  <properties>
634   <duration>
635    <duration>P1D</duration>
636   </duration>
637  </properties>
638 </vcalendar>
639</icalendar>
640XML
641,
642            'BEGIN:VCALENDAR' . "\n" .
643            'DURATION:P1D' . "\n" .
644            'END:VCALENDAR' . "\n"
645        );
646
647    }
648
649    /**
650     * Values, Float.
651     */
652    function testRFC6321Section3_6_7() {
653
654        // GEO uses <float /> with a positive and a non-negative numbers.
655        $this->testRFC6321Section3_4_1_2();
656
657    }
658
659    /**
660     * Values, Integer.
661     */
662    function testRFC6321Section3_6_8() {
663
664        $this->assertXMLEqualsToMimeDir(
665<<<XML
666<?xml version="1.0" encoding="UTF-8"?>
667<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0">
668 <vcalendar>
669  <properties>
670   <foo>
671    <integer>42</integer>
672   </foo>
673  </properties>
674 </vcalendar>
675</icalendar>
676XML
677,
678            'BEGIN:VCALENDAR' . "\n" .
679            'FOO:42' . "\n" .
680            'END:VCALENDAR' . "\n"
681        );
682
683        $this->assertXMLEqualsToMimeDir(
684<<<XML
685<?xml version="1.0" encoding="UTF-8"?>
686<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0">
687 <vcalendar>
688  <properties>
689   <foo>
690    <integer>-42</integer>
691   </foo>
692  </properties>
693 </vcalendar>
694</icalendar>
695XML
696,
697            'BEGIN:VCALENDAR' . "\n" .
698            'FOO:-42' . "\n" .
699            'END:VCALENDAR' . "\n"
700        );
701
702    }
703
704    /**
705     * Values, Period of Time.
706     */
707    function testRFC6321Section3_6_9() {
708
709        $this->assertXMLReflexivelyEqualsToMimeDir(
710<<<XML
711<?xml version="1.0" encoding="UTF-8"?>
712<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0">
713 <vcalendar>
714  <properties>
715   <freebusy>
716    <period>
717     <start>2011-05-17T12:00:00</start>
718     <duration>P1H</duration>
719    </period>
720   </freebusy>
721  </properties>
722 </vcalendar>
723</icalendar>
724XML
725,
726            'BEGIN:VCALENDAR' . "\n" .
727            'FREEBUSY:20110517T120000/P1H' . "\n" .
728            'END:VCALENDAR' . "\n"
729        );
730
731        $this->assertXMLReflexivelyEqualsToMimeDir(
732<<<XML
733<?xml version="1.0" encoding="UTF-8"?>
734<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0">
735 <vcalendar>
736  <properties>
737   <freebusy>
738    <period>
739     <start>2011-05-17T12:00:00</start>
740     <end>2012-05-17T12:00:00</end>
741    </period>
742   </freebusy>
743  </properties>
744 </vcalendar>
745</icalendar>
746XML
747,
748            'BEGIN:VCALENDAR' . "\n" .
749            'FREEBUSY:20110517T120000/20120517T120000' . "\n" .
750            'END:VCALENDAR' . "\n"
751        );
752
753    }
754
755    /**
756     * Values, Recurrence Rule.
757     */
758    function testRFC6321Section3_6_10() {
759
760        $this->assertXMLReflexivelyEqualsToMimeDir(
761<<<XML
762<?xml version="1.0" encoding="UTF-8"?>
763<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0">
764 <vcalendar>
765  <properties>
766   <rrule>
767    <recur>
768     <freq>YEARLY</freq>
769     <count>5</count>
770     <byday>-1SU</byday>
771     <bymonth>10</bymonth>
772    </recur>
773   </rrule>
774  </properties>
775 </vcalendar>
776</icalendar>
777XML
778,
779            'BEGIN:VCALENDAR' . "\n" .
780            'RRULE:FREQ=YEARLY;COUNT=5;BYDAY=-1SU;BYMONTH=10' . "\n" .
781            'END:VCALENDAR' . "\n"
782        );
783
784    }
785
786    /**
787     * Values, Text.
788     */
789    function testRFC6321Section3_6_11() {
790
791        $this->assertXMLReflexivelyEqualsToMimeDir(
792<<<XML
793<?xml version="1.0" encoding="UTF-8"?>
794<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0">
795 <vcalendar>
796  <properties>
797   <calscale>
798    <text>GREGORIAN</text>
799   </calscale>
800  </properties>
801 </vcalendar>
802</icalendar>
803XML
804,
805            'BEGIN:VCALENDAR' . "\n" .
806            'CALSCALE:GREGORIAN' . "\n" .
807            'END:VCALENDAR' . "\n"
808        );
809
810    }
811
812    /**
813     * Values, Time.
814     */
815    function testRFC6321Section3_6_12() {
816
817        $this->assertXMLEqualsToMimeDir(
818<<<XML
819<?xml version="1.0" encoding="UTF-8"?>
820<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0">
821 <vcalendar>
822  <properties>
823   <foo>
824    <time>12:00:00</time>
825   </foo>
826  </properties>
827 </vcalendar>
828</icalendar>
829XML
830,
831            'BEGIN:VCALENDAR' . "\n" .
832            'FOO:120000' . "\n" .
833            'END:VCALENDAR' . "\n"
834        );
835
836    }
837
838    /**
839     * Values, URI.
840     */
841    function testRFC6321Section3_6_13() {
842
843        $this->assertXMLReflexivelyEqualsToMimeDir(
844<<<XML
845<?xml version="1.0" encoding="UTF-8"?>
846<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0">
847 <vcalendar>
848  <properties>
849   <attach>
850    <uri>http://calendar.example.com</uri>
851   </attach>
852  </properties>
853 </vcalendar>
854</icalendar>
855XML
856,
857            'BEGIN:VCALENDAR' . "\n" .
858            'ATTACH:http://calendar.example.com' . "\n" .
859            'END:VCALENDAR' . "\n"
860        );
861
862    }
863
864    /**
865     * Values, UTC Offset.
866     */
867    function testRFC6321Section3_6_14() {
868
869        // Example 1 of RFC5545, Section 3.3.14.
870        $this->assertXMLReflexivelyEqualsToMimeDir(
871<<<XML
872<?xml version="1.0" encoding="UTF-8"?>
873<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0">
874 <vcalendar>
875  <properties>
876   <tzoffsetfrom>
877    <utc-offset>-05:00</utc-offset>
878   </tzoffsetfrom>
879  </properties>
880 </vcalendar>
881</icalendar>
882XML
883,
884            'BEGIN:VCALENDAR' . "\n" .
885            'TZOFFSETFROM:-0500' . "\n" .
886            'END:VCALENDAR' . "\n"
887        );
888
889        // Example 2 of RFC5545, Section 3.3.14.
890        $this->assertXMLReflexivelyEqualsToMimeDir(
891<<<XML
892<?xml version="1.0" encoding="UTF-8"?>
893<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0">
894 <vcalendar>
895  <properties>
896   <tzoffsetfrom>
897    <utc-offset>+01:00</utc-offset>
898   </tzoffsetfrom>
899  </properties>
900 </vcalendar>
901</icalendar>
902XML
903,
904            'BEGIN:VCALENDAR' . "\n" .
905            'TZOFFSETFROM:+0100' . "\n" .
906            'END:VCALENDAR' . "\n"
907        );
908
909    }
910
911    /**
912     * Handling Unrecognized Properties or Parameters.
913     */
914    function testRFC6321Section5() {
915
916        $this->assertXMLReflexivelyEqualsToMimeDir(
917<<<XML
918<?xml version="1.0" encoding="UTF-8"?>
919<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0">
920 <vcalendar>
921  <properties>
922   <x-property>
923    <unknown>20110512T120000Z</unknown>
924   </x-property>
925  </properties>
926 </vcalendar>
927</icalendar>
928XML
929,
930            'BEGIN:VCALENDAR' . "\n" .
931            'X-PROPERTY:20110512T120000Z' . "\n" .
932            'END:VCALENDAR' . "\n"
933        );
934
935        $this->assertXMLReflexivelyEqualsToMimeDir(
936<<<XML
937<?xml version="1.0" encoding="UTF-8"?>
938<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0">
939 <vcalendar>
940  <properties>
941   <dtstart>
942    <parameters>
943     <x-param>
944      <text>PT30M</text>
945     </x-param>
946    </parameters>
947    <date-time>2011-05-12T13:00:00Z</date-time>
948   </dtstart>
949  </properties>
950 </vcalendar>
951</icalendar>
952XML
953,
954            'BEGIN:VCALENDAR' . "\n" .
955            'DTSTART;X-PARAM=PT30M:20110512T130000Z' . "\n" .
956            'END:VCALENDAR' . "\n"
957        );
958
959    }
960
961    function testRDateWithDateTime() {
962
963        $this->assertXMLReflexivelyEqualsToMimeDir(
964<<<XML
965<?xml version="1.0" encoding="UTF-8"?>
966<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0">
967 <vcalendar>
968  <properties>
969   <rdate>
970    <date-time>2008-02-05T19:12:24Z</date-time>
971   </rdate>
972  </properties>
973 </vcalendar>
974</icalendar>
975XML
976,
977            'BEGIN:VCALENDAR' . "\n" .
978            'RDATE:20080205T191224Z' . "\n" .
979            'END:VCALENDAR' . "\n"
980        );
981
982        $this->assertXMLReflexivelyEqualsToMimeDir(
983<<<XML
984<?xml version="1.0" encoding="UTF-8"?>
985<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0">
986 <vcalendar>
987  <properties>
988   <rdate>
989    <date-time>2008-02-05T19:12:24Z</date-time>
990    <date-time>2009-02-05T19:12:24Z</date-time>
991   </rdate>
992  </properties>
993 </vcalendar>
994</icalendar>
995XML
996,
997            'BEGIN:VCALENDAR' . "\n" .
998            'RDATE:20080205T191224Z,20090205T191224Z' . "\n" .
999            'END:VCALENDAR' . "\n"
1000        );
1001
1002    }
1003
1004    function testRDateWithDate() {
1005
1006        $this->assertXMLEqualsToMimeDir(
1007<<<XML
1008<?xml version="1.0" encoding="UTF-8"?>
1009<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0">
1010 <vcalendar>
1011  <properties>
1012   <rdate>
1013    <date>2008-10-06</date>
1014   </rdate>
1015  </properties>
1016 </vcalendar>
1017</icalendar>
1018XML
1019,
1020            'BEGIN:VCALENDAR' . "\n" .
1021            'RDATE:20081006' . "\n" .
1022            'END:VCALENDAR' . "\n"
1023        );
1024
1025        $this->assertXMLEqualsToMimeDir(
1026<<<XML
1027<?xml version="1.0" encoding="UTF-8"?>
1028<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0">
1029 <vcalendar>
1030  <properties>
1031   <rdate>
1032    <date>2008-10-06</date>
1033    <date>2009-10-06</date>
1034    <date>2010-10-06</date>
1035   </rdate>
1036  </properties>
1037 </vcalendar>
1038</icalendar>
1039XML
1040,
1041            'BEGIN:VCALENDAR' . "\n" .
1042            'RDATE:20081006,20091006,20101006' . "\n" .
1043            'END:VCALENDAR' . "\n"
1044        );
1045
1046    }
1047
1048    function testRDateWithPeriod() {
1049
1050        $this->assertXMLReflexivelyEqualsToMimeDir(
1051<<<XML
1052<?xml version="1.0" encoding="UTF-8"?>
1053<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0">
1054 <vcalendar>
1055  <properties>
1056   <rdate>
1057    <parameters>
1058     <tzid>
1059      <text>US/Eastern</text>
1060     </tzid>
1061    </parameters>
1062    <period>
1063     <start>2006-01-02T15:00:00</start>
1064     <duration>PT2H</duration>
1065    </period>
1066   </rdate>
1067  </properties>
1068 </vcalendar>
1069</icalendar>
1070XML
1071,
1072            'BEGIN:VCALENDAR' . "\n" .
1073            'RDATE;TZID=US/Eastern;VALUE=PERIOD:20060102T150000/PT2H' . "\n" .
1074            'END:VCALENDAR' . "\n"
1075        );
1076
1077        $this->assertXMLEqualsToMimeDir(
1078<<<XML
1079<?xml version="1.0" encoding="UTF-8"?>
1080<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0">
1081 <vcalendar>
1082  <properties>
1083   <rdate>
1084    <parameters>
1085     <tzid>
1086      <text>US/Eastern</text>
1087     </tzid>
1088    </parameters>
1089    <period>
1090     <start>2006-01-02T15:00:00</start>
1091     <duration>PT2H</duration>
1092    </period>
1093    <period>
1094     <start>2008-01-02T15:00:00</start>
1095     <duration>PT1H</duration>
1096    </period>
1097   </rdate>
1098  </properties>
1099 </vcalendar>
1100</icalendar>
1101XML
1102,
1103            'BEGIN:VCALENDAR' . "\n" .
1104            'RDATE;TZID=US/Eastern;VALUE=PERIOD:20060102T150000/PT2H,20080102T150000/PT1' . "\n" .
1105            ' H' . "\n" .
1106            'END:VCALENDAR' . "\n"
1107        );
1108
1109    }
1110
1111    /**
1112     * Basic example.
1113     */
1114    function testRFC6351Basic() {
1115
1116        $this->assertXMLReflexivelyEqualsToMimeDir(
1117<<<XML
1118<?xml version="1.0" encoding="UTF-8"?>
1119<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
1120 <vcard>
1121  <fn>
1122   <text>J. Doe</text>
1123  </fn>
1124  <n>
1125   <surname>Doe</surname>
1126   <given>J.</given>
1127   <additional/>
1128   <prefix/>
1129   <suffix/>
1130  </n>
1131 </vcard>
1132</vcards>
1133XML
1134,
1135            'BEGIN:VCARD' . "\n" .
1136            'VERSION:4.0' . "\n" .
1137            'FN:J. Doe' . "\n" .
1138            'N:Doe;J.;;;' . "\n" .
1139            'END:VCARD' . "\n"
1140        );
1141
1142    }
1143
1144    /**
1145     * Example 1.
1146     */
1147    function testRFC6351Example1() {
1148
1149        $this->assertXMLReflexivelyEqualsToMimeDir(
1150<<<XML
1151<?xml version="1.0" encoding="UTF-8"?>
1152<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
1153 <vcard>
1154  <fn>
1155   <text>J. Doe</text>
1156  </fn>
1157  <n>
1158   <surname>Doe</surname>
1159   <given>J.</given>
1160   <additional/>
1161   <prefix/>
1162   <suffix/>
1163  </n>
1164  <x-file>
1165   <parameters>
1166    <mediatype>
1167     <text>image/jpeg</text>
1168    </mediatype>
1169   </parameters>
1170   <unknown>alien.jpg</unknown>
1171  </x-file>
1172  <x1:a href="http://www.example.com" xmlns:x1="http://www.w3.org/1999/xhtml">My web page!</x1:a>
1173 </vcard>
1174</vcards>
1175XML
1176,
1177            'BEGIN:VCARD' . "\n" .
1178            'VERSION:4.0' . "\n" .
1179            'FN:J. Doe' . "\n" .
1180            'N:Doe;J.;;;' . "\n" .
1181            'X-FILE;MEDIATYPE=image/jpeg:alien.jpg' . "\n" .
1182            'XML:<a xmlns="http://www.w3.org/1999/xhtml" href="http://www.example.com">M' . "\n" .
1183            ' y web page!</a>' . "\n" .
1184            'END:VCARD' . "\n"
1185        );
1186
1187    }
1188
1189    /**
1190     * Design Considerations.
1191     */
1192    function testRFC6351Section5() {
1193
1194        $this->assertXMLEqualsToMimeDir(
1195<<<XML
1196<?xml version="1.0" encoding="UTF-8"?>
1197<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
1198 <vcard>
1199  <tel>
1200   <parameters>
1201    <type>
1202     <text>voice</text>
1203     <text>video</text>
1204    </type>
1205   </parameters>
1206   <uri>tel:+1-555-555-555</uri>
1207  </tel>
1208 </vcard>
1209</vcards>
1210XML
1211,
1212            'BEGIN:VCARD' . "\n" .
1213            'VERSION:4.0' . "\n" .
1214            'TEL;TYPE="voice,video":tel:+1-555-555-555' . "\n" .
1215            'END:VCARD' . "\n"
1216        );
1217
1218        $this->assertXMLReflexivelyEqualsToMimeDir(
1219<<<XML
1220<?xml version="1.0" encoding="UTF-8"?>
1221<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
1222 <vcard>
1223  <tel>
1224   <parameters>
1225    <type>
1226     <text>voice</text>
1227     <text>video</text>
1228    </type>
1229   </parameters>
1230   <text>tel:+1-555-555-555</text>
1231  </tel>
1232 </vcard>
1233</vcards>
1234XML
1235,
1236            'BEGIN:VCARD' . "\n" .
1237            'VERSION:4.0' . "\n" .
1238            'TEL;TYPE="voice,video":tel:+1-555-555-555' . "\n" .
1239            'END:VCARD' . "\n"
1240        );
1241
1242    }
1243
1244    /**
1245     * Design Considerations.
1246     */
1247    function testRFC6351Section5Group() {
1248
1249        $this->assertXMLReflexivelyEqualsToMimeDir(
1250<<<XML
1251<?xml version="1.0" encoding="UTF-8"?>
1252<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
1253 <vcard>
1254  <tel>
1255   <text>tel:+1-555-555-556</text>
1256  </tel>
1257  <group name="contact">
1258   <tel>
1259    <text>tel:+1-555-555-555</text>
1260   </tel>
1261   <fn>
1262    <text>Gordon</text>
1263   </fn>
1264  </group>
1265  <group name="media">
1266   <fn>
1267    <text>Gordon</text>
1268   </fn>
1269  </group>
1270 </vcard>
1271</vcards>
1272XML
1273,
1274            'BEGIN:VCARD' . "\n" .
1275            'VERSION:4.0' . "\n" .
1276            'TEL:tel:+1-555-555-556' . "\n" .
1277            'contact.TEL:tel:+1-555-555-555' . "\n" .
1278            'contact.FN:Gordon' . "\n" .
1279            'media.FN:Gordon' . "\n" .
1280            'END:VCARD' . "\n"
1281        );
1282
1283    }
1284
1285    /**
1286     * Extensibility.
1287     */
1288    function testRFC6351Section5_1_NoNamespace() {
1289
1290        $this->assertXMLEqualsToMimeDir(
1291<<<XML
1292<?xml version="1.0" encoding="UTF-8"?>
1293<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
1294 <vcard>
1295  <x-my-prop>
1296   <parameters>
1297    <pref>
1298     <integer>1</integer>
1299    </pref>
1300   </parameters>
1301   <text>value goes here</text>
1302  </x-my-prop>
1303 </vcard>
1304</vcards>
1305XML
1306,
1307            'BEGIN:VCARD' . "\n" .
1308            'VERSION:4.0' . "\n" .
1309            'X-MY-PROP;PREF=1:value goes here' . "\n" .
1310            'END:VCARD' . "\n"
1311        );
1312
1313    }
1314
1315    /**
1316     * Section 4.3.1 of Relax NG Schema: value-date.
1317     */
1318    function testRFC6351ValueDateWithYearMonthDay() {
1319
1320        $this->assertXMLReflexivelyEqualsToMimeDir(
1321<<<XML
1322<?xml version="1.0" encoding="UTF-8"?>
1323<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
1324 <vcard>
1325  <bday>
1326   <date-and-or-time>20150128</date-and-or-time>
1327  </bday>
1328 </vcard>
1329</vcards>
1330XML
1331,
1332            'BEGIN:VCARD' . "\n" .
1333            'VERSION:4.0' . "\n" .
1334            'BDAY:20150128' . "\n" .
1335            'END:VCARD' . "\n"
1336        );
1337
1338    }
1339
1340    /**
1341     * Section 4.3.1 of Relax NG Schema: value-date.
1342     */
1343    function testRFC6351ValueDateWithYearMonth() {
1344
1345        $this->assertXMLReflexivelyEqualsToMimeDir(
1346<<<XML
1347<?xml version="1.0" encoding="UTF-8"?>
1348<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
1349 <vcard>
1350  <bday>
1351   <date-and-or-time>2015-01</date-and-or-time>
1352  </bday>
1353 </vcard>
1354</vcards>
1355XML
1356,
1357            'BEGIN:VCARD' . "\n" .
1358            'VERSION:4.0' . "\n" .
1359            'BDAY:2015-01' . "\n" .
1360            'END:VCARD' . "\n"
1361        );
1362
1363    }
1364
1365    /**
1366     * Section 4.3.1 of Relax NG Schema: value-date.
1367     */
1368    function testRFC6351ValueDateWithMonth() {
1369
1370        $this->assertXMLReflexivelyEqualsToMimeDir(
1371<<<XML
1372<?xml version="1.0" encoding="UTF-8"?>
1373<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
1374 <vcard>
1375  <bday>
1376   <date-and-or-time>--01</date-and-or-time>
1377  </bday>
1378 </vcard>
1379</vcards>
1380XML
1381,
1382            'BEGIN:VCARD' . "\n" .
1383            'VERSION:4.0' . "\n" .
1384            'BDAY:--01' . "\n" .
1385            'END:VCARD' . "\n"
1386        );
1387
1388    }
1389
1390    /**
1391     * Section 4.3.1 of Relax NG Schema: value-date.
1392     */
1393    function testRFC6351ValueDateWithMonthDay() {
1394
1395        $this->assertXMLReflexivelyEqualsToMimeDir(
1396<<<XML
1397<?xml version="1.0" encoding="UTF-8"?>
1398<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
1399 <vcard>
1400  <bday>
1401   <date-and-or-time>--0128</date-and-or-time>
1402  </bday>
1403 </vcard>
1404</vcards>
1405XML
1406,
1407            'BEGIN:VCARD' . "\n" .
1408            'VERSION:4.0' . "\n" .
1409            'BDAY:--0128' . "\n" .
1410            'END:VCARD' . "\n"
1411        );
1412
1413    }
1414
1415    /**
1416     * Section 4.3.1 of Relax NG Schema: value-date.
1417     */
1418    function testRFC6351ValueDateWithDay() {
1419
1420        $this->assertXMLReflexivelyEqualsToMimeDir(
1421<<<XML
1422<?xml version="1.0" encoding="UTF-8"?>
1423<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
1424 <vcard>
1425  <bday>
1426   <date-and-or-time>---28</date-and-or-time>
1427  </bday>
1428 </vcard>
1429</vcards>
1430XML
1431,
1432            'BEGIN:VCARD' . "\n" .
1433            'VERSION:4.0' . "\n" .
1434            'BDAY:---28' . "\n" .
1435            'END:VCARD' . "\n"
1436        );
1437
1438    }
1439
1440    /**
1441     * Section 4.3.2 of Relax NG Schema: value-time.
1442     */
1443    function testRFC6351ValueTimeWithHour() {
1444
1445        $this->assertXMLReflexivelyEqualsToMimeDir(
1446<<<XML
1447<?xml version="1.0" encoding="UTF-8"?>
1448<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
1449 <vcard>
1450  <bday>
1451   <date-and-or-time>13</date-and-or-time>
1452  </bday>
1453 </vcard>
1454</vcards>
1455XML
1456,
1457            'BEGIN:VCARD' . "\n" .
1458            'VERSION:4.0' . "\n" .
1459            'BDAY:13' . "\n" .
1460            'END:VCARD' . "\n"
1461        );
1462
1463    }
1464
1465    /**
1466     * Section 4.3.2 of Relax NG Schema: value-time.
1467     */
1468    function testRFC6351ValueTimeWithHourMinute() {
1469
1470        $this->assertXMLReflexivelyEqualsToMimeDir(
1471<<<XML
1472<?xml version="1.0" encoding="UTF-8"?>
1473<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
1474 <vcard>
1475  <bday>
1476   <date-and-or-time>1353</date-and-or-time>
1477  </bday>
1478 </vcard>
1479</vcards>
1480XML
1481,
1482            'BEGIN:VCARD' . "\n" .
1483            'VERSION:4.0' . "\n" .
1484            'BDAY:1353' . "\n" .
1485            'END:VCARD' . "\n"
1486        );
1487
1488    }
1489
1490    /**
1491     * Section 4.3.2 of Relax NG Schema: value-time.
1492     */
1493    function testRFC6351ValueTimeWithHourMinuteSecond() {
1494
1495        $this->assertXMLReflexivelyEqualsToMimeDir(
1496<<<XML
1497<?xml version="1.0" encoding="UTF-8"?>
1498<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
1499 <vcard>
1500  <bday>
1501   <date-and-or-time>135301</date-and-or-time>
1502  </bday>
1503 </vcard>
1504</vcards>
1505XML
1506,
1507            'BEGIN:VCARD' . "\n" .
1508            'VERSION:4.0' . "\n" .
1509            'BDAY:135301' . "\n" .
1510            'END:VCARD' . "\n"
1511        );
1512
1513    }
1514
1515    /**
1516     * Section 4.3.2 of Relax NG Schema: value-time.
1517     */
1518    function testRFC6351ValueTimeWithMinute() {
1519
1520        $this->assertXMLReflexivelyEqualsToMimeDir(
1521<<<XML
1522<?xml version="1.0" encoding="UTF-8"?>
1523<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
1524 <vcard>
1525  <bday>
1526   <date-and-or-time>-53</date-and-or-time>
1527  </bday>
1528 </vcard>
1529</vcards>
1530XML
1531,
1532            'BEGIN:VCARD' . "\n" .
1533            'VERSION:4.0' . "\n" .
1534            'BDAY:-53' . "\n" .
1535            'END:VCARD' . "\n"
1536        );
1537
1538    }
1539
1540    /**
1541     * Section 4.3.2 of Relax NG Schema: value-time.
1542     */
1543    function testRFC6351ValueTimeWithMinuteSecond() {
1544
1545        $this->assertXMLReflexivelyEqualsToMimeDir(
1546<<<XML
1547<?xml version="1.0" encoding="UTF-8"?>
1548<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
1549 <vcard>
1550  <bday>
1551   <date-and-or-time>-5301</date-and-or-time>
1552  </bday>
1553 </vcard>
1554</vcards>
1555XML
1556,
1557            'BEGIN:VCARD' . "\n" .
1558            'VERSION:4.0' . "\n" .
1559            'BDAY:-5301' . "\n" .
1560            'END:VCARD' . "\n"
1561        );
1562
1563    }
1564
1565    /**
1566     * Section 4.3.2 of Relax NG Schema: value-time.
1567     */
1568    function testRFC6351ValueTimeWithSecond() {
1569
1570        $this->assertTrue(true);
1571
1572        /*
1573         * According to the Relax NG Schema, there is a conflict between
1574         * value-date and value-time. The --01 syntax can only match a
1575         * value-date because of the higher priority set in
1576         * value-date-and-or-time. So we basically skip this test.
1577         *
1578        $this->assertXMLReflexivelyEqualsToMimeDir(
1579<<<XML
1580<?xml version="1.0" encoding="UTF-8"?>
1581<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
1582 <vcard>
1583  <bday>
1584   <date-and-or-time>--01</date-and-or-time>
1585  </bday>
1586 </vcard>
1587</vcards>
1588XML
1589,
1590            'BEGIN:VCARD' . "\n" .
1591            'VERSION:4.0' . "\n" .
1592            'BDAY:--01' . "\n" .
1593            'END:VCARD' . "\n"
1594        );
1595        */
1596
1597    }
1598
1599    /**
1600     * Section 4.3.2 of Relax NG Schema: value-time.
1601     */
1602    function testRFC6351ValueTimeWithSecondZ() {
1603
1604        $this->assertXMLReflexivelyEqualsToMimeDir(
1605<<<XML
1606<?xml version="1.0" encoding="UTF-8"?>
1607<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
1608 <vcard>
1609  <bday>
1610   <date-and-or-time>--01Z</date-and-or-time>
1611  </bday>
1612 </vcard>
1613</vcards>
1614XML
1615,
1616            'BEGIN:VCARD' . "\n" .
1617            'VERSION:4.0' . "\n" .
1618            'BDAY:--01Z' . "\n" .
1619            'END:VCARD' . "\n"
1620        );
1621
1622    }
1623
1624    /**
1625     * Section 4.3.2 of Relax NG Schema: value-time.
1626     */
1627    function testRFC6351ValueTimeWithSecondTZ() {
1628
1629        $this->assertXMLReflexivelyEqualsToMimeDir(
1630<<<XML
1631<?xml version="1.0" encoding="UTF-8"?>
1632<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
1633 <vcard>
1634  <bday>
1635   <date-and-or-time>--01+1234</date-and-or-time>
1636  </bday>
1637 </vcard>
1638</vcards>
1639XML
1640,
1641            'BEGIN:VCARD' . "\n" .
1642            'VERSION:4.0' . "\n" .
1643            'BDAY:--01+1234' . "\n" .
1644            'END:VCARD' . "\n"
1645        );
1646
1647    }
1648
1649    /**
1650     * Section 4.3.3 of Relax NG Schema: value-date-time.
1651     */
1652    function testRFC6351ValueDateTimeWithYearMonthDayHour() {
1653
1654        $this->assertXMLReflexivelyEqualsToMimeDir(
1655<<<XML
1656<?xml version="1.0" encoding="UTF-8"?>
1657<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
1658 <vcard>
1659  <bday>
1660   <date-and-or-time>20150128T13</date-and-or-time>
1661  </bday>
1662 </vcard>
1663</vcards>
1664XML
1665,
1666            'BEGIN:VCARD' . "\n" .
1667            'VERSION:4.0' . "\n" .
1668            'BDAY:20150128T13' . "\n" .
1669            'END:VCARD' . "\n"
1670        );
1671
1672    }
1673
1674    /**
1675     * Section 4.3.3 of Relax NG Schema: value-date-time.
1676     */
1677    function testRFC6351ValueDateTimeWithMonthDayHour() {
1678
1679        $this->assertXMLReflexivelyEqualsToMimeDir(
1680<<<XML
1681<?xml version="1.0" encoding="UTF-8"?>
1682<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
1683 <vcard>
1684  <bday>
1685   <date-and-or-time>--0128T13</date-and-or-time>
1686  </bday>
1687 </vcard>
1688</vcards>
1689XML
1690,
1691            'BEGIN:VCARD' . "\n" .
1692            'VERSION:4.0' . "\n" .
1693            'BDAY:--0128T13' . "\n" .
1694            'END:VCARD' . "\n"
1695        );
1696
1697    }
1698
1699    /**
1700     * Section 4.3.3 of Relax NG Schema: value-date-time.
1701     */
1702    function testRFC6351ValueDateTimeWithDayHour() {
1703
1704        $this->assertXMLReflexivelyEqualsToMimeDir(
1705<<<XML
1706<?xml version="1.0" encoding="UTF-8"?>
1707<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
1708 <vcard>
1709  <bday>
1710   <date-and-or-time>---28T13</date-and-or-time>
1711  </bday>
1712 </vcard>
1713</vcards>
1714XML
1715,
1716            'BEGIN:VCARD' . "\n" .
1717            'VERSION:4.0' . "\n" .
1718            'BDAY:---28T13' . "\n" .
1719            'END:VCARD' . "\n"
1720        );
1721
1722    }
1723
1724    /**
1725     * Section 4.3.3 of Relax NG Schema: value-date-time.
1726     */
1727    function testRFC6351ValueDateTimeWithDayHourMinute() {
1728
1729        $this->assertXMLReflexivelyEqualsToMimeDir(
1730<<<XML
1731<?xml version="1.0" encoding="UTF-8"?>
1732<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
1733 <vcard>
1734  <bday>
1735   <date-and-or-time>---28T1353</date-and-or-time>
1736  </bday>
1737 </vcard>
1738</vcards>
1739XML
1740,
1741            'BEGIN:VCARD' . "\n" .
1742            'VERSION:4.0' . "\n" .
1743            'BDAY:---28T1353' . "\n" .
1744            'END:VCARD' . "\n"
1745        );
1746
1747    }
1748
1749    /**
1750     * Section 4.3.3 of Relax NG Schema: value-date-time.
1751     */
1752    function testRFC6351ValueDateTimeWithDayHourMinuteSecond() {
1753
1754        $this->assertXMLReflexivelyEqualsToMimeDir(
1755<<<XML
1756<?xml version="1.0" encoding="UTF-8"?>
1757<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
1758 <vcard>
1759  <bday>
1760   <date-and-or-time>---28T135301</date-and-or-time>
1761  </bday>
1762 </vcard>
1763</vcards>
1764XML
1765,
1766            'BEGIN:VCARD' . "\n" .
1767            'VERSION:4.0' . "\n" .
1768            'BDAY:---28T135301' . "\n" .
1769            'END:VCARD' . "\n"
1770        );
1771
1772    }
1773
1774    /**
1775     * Section 4.3.3 of Relax NG Schema: value-date-time.
1776     */
1777    function testRFC6351ValueDateTimeWithDayHourZ() {
1778
1779        $this->assertXMLReflexivelyEqualsToMimeDir(
1780<<<XML
1781<?xml version="1.0" encoding="UTF-8"?>
1782<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
1783 <vcard>
1784  <bday>
1785   <date-and-or-time>---28T13Z</date-and-or-time>
1786  </bday>
1787 </vcard>
1788</vcards>
1789XML
1790,
1791            'BEGIN:VCARD' . "\n" .
1792            'VERSION:4.0' . "\n" .
1793            'BDAY:---28T13Z' . "\n" .
1794            'END:VCARD' . "\n"
1795        );
1796
1797    }
1798
1799    /**
1800     * Section 4.3.3 of Relax NG Schema: value-date-time.
1801     */
1802    function testRFC6351ValueDateTimeWithDayHourTZ() {
1803
1804        $this->assertXMLReflexivelyEqualsToMimeDir(
1805<<<XML
1806<?xml version="1.0" encoding="UTF-8"?>
1807<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
1808 <vcard>
1809  <bday>
1810   <date-and-or-time>---28T13+1234</date-and-or-time>
1811  </bday>
1812 </vcard>
1813</vcards>
1814XML
1815,
1816            'BEGIN:VCARD' . "\n" .
1817            'VERSION:4.0' . "\n" .
1818            'BDAY:---28T13+1234' . "\n" .
1819            'END:VCARD' . "\n"
1820        );
1821
1822    }
1823
1824    /**
1825     * Property: SOURCE.
1826     */
1827    function testRFC6350Section6_1_3() {
1828
1829        $this->assertXMLReflexivelyEqualsToMimeDir(
1830<<<XML
1831<?xml version="1.0" encoding="UTF-8"?>
1832<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
1833 <vcard>
1834  <source>
1835   <uri>ldap://ldap.example.com/cn=Babs%20Jensen,%20o=Babsco,%20c=US</uri>
1836  </source>
1837 </vcard>
1838</vcards>
1839XML
1840,
1841            'BEGIN:VCARD' . "\n" .
1842            'VERSION:4.0' . "\n" .
1843            'SOURCE:ldap://ldap.example.com/cn=Babs%20Jensen\,%20o=Babsco\,%20c=US' . "\n" .
1844            'END:VCARD' . "\n"
1845        );
1846
1847    }
1848
1849    /**
1850     * Property: KIND.
1851     */
1852    function testRFC6350Section6_1_4() {
1853
1854        $this->assertXMLReflexivelyEqualsToMimeDir(
1855<<<XML
1856<?xml version="1.0" encoding="UTF-8"?>
1857<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
1858 <vcard>
1859  <kind>
1860   <text>individual</text>
1861  </kind>
1862 </vcard>
1863</vcards>
1864XML
1865,
1866            'BEGIN:VCARD' . "\n" .
1867            'VERSION:4.0' . "\n" .
1868            'KIND:individual' . "\n" .
1869            'END:VCARD' . "\n"
1870        );
1871
1872    }
1873
1874    /**
1875     * Property: FN.
1876     */
1877    function testRFC6350Section6_2_1() {
1878
1879        $this->assertXMLReflexivelyEqualsToMimeDir(
1880<<<XML
1881<?xml version="1.0" encoding="UTF-8"?>
1882<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
1883 <vcard>
1884  <fn>
1885   <text>Mr. John Q. Public, Esq.</text>
1886  </fn>
1887 </vcard>
1888</vcards>
1889XML
1890,
1891            'BEGIN:VCARD' . "\n" .
1892            'VERSION:4.0' . "\n" .
1893            'FN:Mr. John Q. Public\, Esq.' . "\n" .
1894            'END:VCARD' . "\n"
1895        );
1896
1897    }
1898
1899    /**
1900     * Property: N.
1901     */
1902    function testRFC6350Section6_2_2() {
1903
1904        $this->assertXMLReflexivelyEqualsToMimeDir(
1905<<<XML
1906<?xml version="1.0" encoding="UTF-8"?>
1907<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
1908 <vcard>
1909  <n>
1910   <surname>Stevenson</surname>
1911   <given>John</given>
1912   <additional>Philip,Paul</additional>
1913   <prefix>Dr.</prefix>
1914   <suffix>Jr.,M.D.,A.C.P.</suffix>
1915  </n>
1916 </vcard>
1917</vcards>
1918XML
1919,
1920            'BEGIN:VCARD' . "\n" .
1921            'VERSION:4.0' . "\n" .
1922            'N:Stevenson;John;Philip\,Paul;Dr.;Jr.\,M.D.\,A.C.P.' . "\n" .
1923            'END:VCARD' . "\n"
1924        );
1925
1926    }
1927
1928    /**
1929     * Property: NICKNAME.
1930     */
1931    function testRFC6350Section6_2_3() {
1932
1933        $this->assertXMLReflexivelyEqualsToMimeDir(
1934<<<XML
1935<?xml version="1.0" encoding="UTF-8"?>
1936<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
1937 <vcard>
1938  <nickname>
1939   <text>Jim</text>
1940   <text>Jimmie</text>
1941  </nickname>
1942 </vcard>
1943</vcards>
1944XML
1945,
1946            'BEGIN:VCARD' . "\n" .
1947            'VERSION:4.0' . "\n" .
1948            'NICKNAME:Jim,Jimmie' . "\n" .
1949            'END:VCARD' . "\n"
1950        );
1951
1952    }
1953
1954    /**
1955     * Property: PHOTO.
1956     */
1957    function testRFC6350Section6_2_4() {
1958
1959        $this->assertXMLReflexivelyEqualsToMimeDir(
1960<<<XML
1961<?xml version="1.0" encoding="UTF-8"?>
1962<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
1963 <vcard>
1964  <photo>
1965   <uri>http://www.example.com/pub/photos/jqpublic.gif</uri>
1966  </photo>
1967 </vcard>
1968</vcards>
1969XML
1970,
1971            'BEGIN:VCARD' . "\n" .
1972            'VERSION:4.0' . "\n" .
1973            'PHOTO:http://www.example.com/pub/photos/jqpublic.gif' . "\n" .
1974            'END:VCARD' . "\n"
1975        );
1976
1977    }
1978
1979    function testRFC6350Section6_2_5() {
1980
1981        $this->assertXMLReflexivelyEqualsToMimeDir(
1982<<<XML
1983<?xml version="1.0" encoding="UTF-8"?>
1984<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
1985 <vcard>
1986  <bday>
1987   <date-and-or-time>19531015T231000Z</date-and-or-time>
1988  </bday>
1989 </vcard>
1990</vcards>
1991XML
1992,
1993            'BEGIN:VCARD' . "\n" .
1994            'VERSION:4.0' . "\n" .
1995            'BDAY:19531015T231000Z' . "\n" .
1996            'END:VCARD' . "\n"
1997        );
1998
1999    }
2000
2001    function testRFC6350Section6_2_6() {
2002
2003        $this->assertXMLReflexivelyEqualsToMimeDir(
2004<<<XML
2005<?xml version="1.0" encoding="UTF-8"?>
2006<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
2007 <vcard>
2008  <anniversary>
2009   <date-and-or-time>19960415</date-and-or-time>
2010  </anniversary>
2011 </vcard>
2012</vcards>
2013XML
2014,
2015            'BEGIN:VCARD' . "\n" .
2016            'VERSION:4.0' . "\n" .
2017            'ANNIVERSARY:19960415' . "\n" .
2018            'END:VCARD' . "\n"
2019        );
2020
2021    }
2022
2023    /**
2024     * Property: GENDER.
2025     */
2026    function testRFC6350Section6_2_7() {
2027
2028        $this->assertXMLReflexivelyEqualsToMimeDir(
2029<<<XML
2030<?xml version="1.0" encoding="UTF-8"?>
2031<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
2032 <vcard>
2033  <gender>
2034   <sex>Jim</sex>
2035   <text>Jimmie</text>
2036  </gender>
2037 </vcard>
2038</vcards>
2039XML
2040,
2041            'BEGIN:VCARD' . "\n" .
2042            'VERSION:4.0' . "\n" .
2043            'GENDER:Jim;Jimmie' . "\n" .
2044            'END:VCARD' . "\n"
2045        );
2046
2047    }
2048
2049    /**
2050     * Property: ADR.
2051     */
2052    function testRFC6350Section6_3_1() {
2053
2054        $this->assertXMLReflexivelyEqualsToMimeDir(
2055<<<XML
2056<?xml version="1.0" encoding="UTF-8"?>
2057<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
2058 <vcard>
2059  <adr>
2060   <pobox/>
2061   <ext/>
2062   <street>123 Main Street</street>
2063   <locality>Any Town</locality>
2064   <region>CA</region>
2065   <code>91921-1234</code>
2066   <country>U.S.A.</country>
2067  </adr>
2068 </vcard>
2069</vcards>
2070XML
2071,
2072            'BEGIN:VCARD' . "\n" .
2073            'VERSION:4.0' . "\n" .
2074            'ADR:;;123 Main Street;Any Town;CA;91921-1234;U.S.A.' . "\n" .
2075            'END:VCARD' . "\n"
2076        );
2077
2078    }
2079
2080    /**
2081     * Property: TEL.
2082     */
2083    function testRFC6350Section6_4_1() {
2084
2085        /**
2086         * Quoting RFC:
2087         * > Value type:  By default, it is a single free-form text value (for
2088         * > backward compatibility with vCard 3), but it SHOULD be reset to a
2089         * > URI value.  It is expected that the URI scheme will be "tel", as
2090         * > specified in [RFC3966], but other schemes MAY be used.
2091         *
2092         * So first, we test xCard/URI to vCard/URI.
2093         * Then, we test xCard/TEXT to vCard/TEXT to xCard/TEXT.
2094         */
2095        $this->assertXMLEqualsToMimeDir(
2096<<<XML
2097<?xml version="1.0" encoding="UTF-8"?>
2098<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
2099 <vcard>
2100  <tel>
2101   <parameters>
2102    <type>
2103     <text>home</text>
2104    </type>
2105   </parameters>
2106   <uri>tel:+33-01-23-45-67</uri>
2107  </tel>
2108 </vcard>
2109</vcards>
2110XML
2111,
2112            'BEGIN:VCARD' . "\n" .
2113            'VERSION:4.0' . "\n" .
2114            'TEL;TYPE=home:tel:+33-01-23-45-67' . "\n" .
2115            'END:VCARD' . "\n"
2116        );
2117
2118        $this->assertXMLReflexivelyEqualsToMimeDir(
2119<<<XML
2120<?xml version="1.0" encoding="UTF-8"?>
2121<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
2122 <vcard>
2123  <tel>
2124   <parameters>
2125    <type>
2126     <text>home</text>
2127    </type>
2128   </parameters>
2129   <text>tel:+33-01-23-45-67</text>
2130  </tel>
2131 </vcard>
2132</vcards>
2133XML
2134,
2135            'BEGIN:VCARD' . "\n" .
2136            'VERSION:4.0' . "\n" .
2137            'TEL;TYPE=home:tel:+33-01-23-45-67' . "\n" .
2138            'END:VCARD' . "\n"
2139        );
2140
2141    }
2142
2143    /**
2144     * Property: EMAIL.
2145     */
2146    function testRFC6350Section6_4_2() {
2147
2148        $this->assertXMLReflexivelyEqualsToMimeDir(
2149<<<XML
2150<?xml version="1.0" encoding="UTF-8"?>
2151<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
2152 <vcard>
2153  <email>
2154   <parameters>
2155    <type>
2156     <text>work</text>
2157    </type>
2158   </parameters>
2159   <text>jqpublic@xyz.example.com</text>
2160  </email>
2161 </vcard>
2162</vcards>
2163XML
2164,
2165            'BEGIN:VCARD' . "\n" .
2166            'VERSION:4.0' . "\n" .
2167            'EMAIL;TYPE=work:jqpublic@xyz.example.com' . "\n" .
2168            'END:VCARD' . "\n"
2169        );
2170
2171    }
2172
2173    /**
2174     * Property: IMPP.
2175     */
2176    function testRFC6350Section6_4_3() {
2177
2178        $this->assertXMLReflexivelyEqualsToMimeDir(
2179<<<XML
2180<?xml version="1.0" encoding="UTF-8"?>
2181<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
2182 <vcard>
2183  <impp>
2184   <parameters>
2185    <pref>
2186     <text>1</text>
2187    </pref>
2188   </parameters>
2189   <uri>xmpp:alice@example.com</uri>
2190  </impp>
2191 </vcard>
2192</vcards>
2193XML
2194,
2195            'BEGIN:VCARD' . "\n" .
2196            'VERSION:4.0' . "\n" .
2197            'IMPP;PREF=1:xmpp:alice@example.com' . "\n" .
2198            'END:VCARD' . "\n"
2199        );
2200
2201    }
2202
2203    /**
2204     * Property: LANG.
2205     */
2206    function testRFC6350Section6_4_4() {
2207
2208        $this->assertXMLReflexivelyEqualsToMimeDir(
2209<<<XML
2210<?xml version="1.0" encoding="UTF-8"?>
2211<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
2212 <vcard>
2213  <lang>
2214   <parameters>
2215    <type>
2216     <text>work</text>
2217    </type>
2218    <pref>
2219     <text>2</text>
2220    </pref>
2221   </parameters>
2222   <language-tag>en</language-tag>
2223  </lang>
2224 </vcard>
2225</vcards>
2226XML
2227,
2228            'BEGIN:VCARD' . "\n" .
2229            'VERSION:4.0' . "\n" .
2230            'LANG;TYPE=work;PREF=2:en' . "\n" .
2231            'END:VCARD' . "\n"
2232        );
2233
2234    }
2235
2236    /**
2237     * Property: TZ.
2238     */
2239    function testRFC6350Section6_5_1() {
2240
2241        $this->assertXMLReflexivelyEqualsToMimeDir(
2242<<<XML
2243<?xml version="1.0" encoding="UTF-8"?>
2244<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
2245 <vcard>
2246  <tz>
2247   <text>Raleigh/North America</text>
2248  </tz>
2249 </vcard>
2250</vcards>
2251XML
2252,
2253            'BEGIN:VCARD' . "\n" .
2254            'VERSION:4.0' . "\n" .
2255            'TZ:Raleigh/North America' . "\n" .
2256            'END:VCARD' . "\n"
2257        );
2258
2259    }
2260
2261    /**
2262     * Property: GEO.
2263     */
2264    function testRFC6350Section6_5_2() {
2265
2266        $this->assertXMLEqualsToMimeDir(
2267<<<XML
2268<?xml version="1.0" encoding="UTF-8"?>
2269<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
2270 <vcard>
2271  <geo>
2272   <uri>geo:37.386013,-122.082932</uri>
2273  </geo>
2274 </vcard>
2275</vcards>
2276XML
2277,
2278            'BEGIN:VCARD' . "\n" .
2279            'VERSION:4.0' . "\n" .
2280            'GEO:geo:37.386013\,-122.082932' . "\n" .
2281            'END:VCARD' . "\n"
2282        );
2283
2284        $this->assertXMLReflexivelyEqualsToMimeDir(
2285<<<XML
2286<?xml version="1.0" encoding="UTF-8"?>
2287<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
2288 <vcard>
2289  <geo>
2290   <text>geo:37.386013,-122.082932</text>
2291  </geo>
2292 </vcard>
2293</vcards>
2294XML
2295,
2296            'BEGIN:VCARD' . "\n" .
2297            'VERSION:4.0' . "\n" .
2298            'GEO:geo:37.386013\,-122.082932' . "\n" .
2299            'END:VCARD' . "\n"
2300        );
2301
2302    }
2303
2304    /**
2305     * Property: TITLE.
2306     */
2307    function testRFC6350Section6_6_1() {
2308
2309        $this->assertXMLReflexivelyEqualsToMimeDir(
2310<<<XML
2311<?xml version="1.0" encoding="UTF-8"?>
2312<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
2313 <vcard>
2314  <title>
2315   <text>Research Scientist</text>
2316  </title>
2317 </vcard>
2318</vcards>
2319XML
2320,
2321            'BEGIN:VCARD' . "\n" .
2322            'VERSION:4.0' . "\n" .
2323            'TITLE:Research Scientist' . "\n" .
2324            'END:VCARD' . "\n"
2325        );
2326
2327    }
2328
2329    /**
2330     * Property: ROLE.
2331     */
2332    function testRFC6350Section6_6_2() {
2333
2334        $this->assertXMLReflexivelyEqualsToMimeDir(
2335<<<XML
2336<?xml version="1.0" encoding="UTF-8"?>
2337<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
2338 <vcard>
2339  <role>
2340   <text>Project Leader</text>
2341  </role>
2342 </vcard>
2343</vcards>
2344XML
2345,
2346            'BEGIN:VCARD' . "\n" .
2347            'VERSION:4.0' . "\n" .
2348            'ROLE:Project Leader' . "\n" .
2349            'END:VCARD' . "\n"
2350        );
2351
2352    }
2353
2354    /**
2355     * Property: LOGO.
2356     */
2357    function testRFC6350Section6_6_3() {
2358
2359        $this->assertXMLReflexivelyEqualsToMimeDir(
2360<<<XML
2361<?xml version="1.0" encoding="UTF-8"?>
2362<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
2363 <vcard>
2364  <logo>
2365   <uri>http://www.example.com/pub/logos/abccorp.jpg</uri>
2366  </logo>
2367 </vcard>
2368</vcards>
2369XML
2370,
2371            'BEGIN:VCARD' . "\n" .
2372            'VERSION:4.0' . "\n" .
2373            'LOGO:http://www.example.com/pub/logos/abccorp.jpg' . "\n" .
2374            'END:VCARD' . "\n"
2375        );
2376
2377    }
2378
2379    /**
2380     * Property: ORG.
2381     */
2382    function testRFC6350Section6_6_4() {
2383
2384        $this->assertXMLReflexivelyEqualsToMimeDir(
2385<<<XML
2386<?xml version="1.0" encoding="UTF-8"?>
2387<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
2388 <vcard>
2389  <org>
2390   <text>ABC, Inc.</text>
2391   <text>North American Division</text>
2392   <text>Marketing</text>
2393  </org>
2394 </vcard>
2395</vcards>
2396XML
2397,
2398            'BEGIN:VCARD' . "\n" .
2399            'VERSION:4.0' . "\n" .
2400            'ORG:ABC\, Inc.;North American Division;Marketing' . "\n" .
2401            'END:VCARD' . "\n"
2402        );
2403
2404    }
2405
2406    /**
2407     * Property: MEMBER.
2408     */
2409    function testRFC6350Section6_6_5() {
2410
2411        $this->assertXMLReflexivelyEqualsToMimeDir(
2412<<<XML
2413<?xml version="1.0" encoding="UTF-8"?>
2414<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
2415 <vcard>
2416  <member>
2417   <uri>urn:uuid:03a0e51f-d1aa-4385-8a53-e29025acd8af</uri>
2418  </member>
2419 </vcard>
2420</vcards>
2421XML
2422,
2423            'BEGIN:VCARD' . "\n" .
2424            'VERSION:4.0' . "\n" .
2425            'MEMBER:urn:uuid:03a0e51f-d1aa-4385-8a53-e29025acd8af' . "\n" .
2426            'END:VCARD' . "\n"
2427        );
2428
2429        $this->assertXMLReflexivelyEqualsToMimeDir(
2430<<<XML
2431<?xml version="1.0" encoding="UTF-8"?>
2432<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
2433 <vcard>
2434  <member>
2435   <uri>mailto:subscriber1@example.com</uri>
2436  </member>
2437  <member>
2438   <uri>xmpp:subscriber2@example.com</uri>
2439  </member>
2440  <member>
2441   <uri>sip:subscriber3@example.com</uri>
2442  </member>
2443  <member>
2444   <uri>tel:+1-418-555-5555</uri>
2445  </member>
2446 </vcard>
2447</vcards>
2448XML
2449,
2450            'BEGIN:VCARD' . "\n" .
2451            'VERSION:4.0' . "\n" .
2452            'MEMBER:mailto:subscriber1@example.com' . "\n" .
2453            'MEMBER:xmpp:subscriber2@example.com' . "\n" .
2454            'MEMBER:sip:subscriber3@example.com' . "\n" .
2455            'MEMBER:tel:+1-418-555-5555' . "\n" .
2456            'END:VCARD' . "\n"
2457        );
2458
2459    }
2460
2461    /**
2462     * Property: RELATED.
2463     */
2464    function testRFC6350Section6_6_6() {
2465
2466        $this->assertXMLReflexivelyEqualsToMimeDir(
2467<<<XML
2468<?xml version="1.0" encoding="UTF-8"?>
2469<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
2470 <vcard>
2471  <related>
2472   <parameters>
2473    <type>
2474     <text>friend</text>
2475    </type>
2476   </parameters>
2477   <uri>urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6</uri>
2478  </related>
2479 </vcard>
2480</vcards>
2481XML
2482,
2483            'BEGIN:VCARD' . "\n" .
2484            'VERSION:4.0' . "\n" .
2485            'RELATED;TYPE=friend:urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6' . "\n" .
2486            'END:VCARD' . "\n"
2487        );
2488
2489    }
2490
2491    /**
2492     * Property: CATEGORIES.
2493     */
2494    function testRFC6350Section6_7_1() {
2495
2496        $this->assertXMLReflexivelyEqualsToMimeDir(
2497<<<XML
2498<?xml version="1.0" encoding="UTF-8"?>
2499<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
2500 <vcard>
2501  <categories>
2502   <text>INTERNET</text>
2503   <text>IETF</text>
2504   <text>INDUSTRY</text>
2505   <text>INFORMATION TECHNOLOGY</text>
2506  </categories>
2507 </vcard>
2508</vcards>
2509XML
2510,
2511            'BEGIN:VCARD' . "\n" .
2512            'VERSION:4.0' . "\n" .
2513            'CATEGORIES:INTERNET,IETF,INDUSTRY,INFORMATION TECHNOLOGY' . "\n" .
2514            'END:VCARD' . "\n"
2515        );
2516
2517    }
2518
2519    /**
2520     * Property: NOTE.
2521     */
2522    function testRFC6350Section6_7_2() {
2523
2524        $this->assertXMLReflexivelyEqualsToMimeDir(
2525<<<XML
2526<?xml version="1.0" encoding="UTF-8"?>
2527<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
2528 <vcard>
2529  <note>
2530   <text>Foo, bar</text>
2531  </note>
2532 </vcard>
2533</vcards>
2534XML
2535,
2536            'BEGIN:VCARD' . "\n" .
2537            'VERSION:4.0' . "\n" .
2538            'NOTE:Foo\, bar' . "\n" .
2539            'END:VCARD' . "\n"
2540        );
2541
2542    }
2543
2544    /**
2545     * Property: PRODID.
2546     */
2547    function testRFC6350Section6_7_3() {
2548
2549        $this->assertXMLReflexivelyEqualsToMimeDir(
2550<<<XML
2551<?xml version="1.0" encoding="UTF-8"?>
2552<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
2553 <vcard>
2554  <prodid>
2555   <text>-//ONLINE DIRECTORY//NONSGML Version 1//EN</text>
2556  </prodid>
2557 </vcard>
2558</vcards>
2559XML
2560,
2561            'BEGIN:VCARD' . "\n" .
2562            'VERSION:4.0' . "\n" .
2563            'PRODID:-//ONLINE DIRECTORY//NONSGML Version 1//EN' . "\n" .
2564            'END:VCARD' . "\n"
2565        );
2566
2567    }
2568
2569    function testRFC6350Section6_7_4() {
2570
2571        $this->assertXMLReflexivelyEqualsToMimeDir(
2572<<<XML
2573<?xml version="1.0" encoding="UTF-8"?>
2574<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
2575 <vcard>
2576  <rev>
2577   <timestamp>19951031T222710Z</timestamp>
2578  </rev>
2579 </vcard>
2580</vcards>
2581XML
2582,
2583            'BEGIN:VCARD' . "\n" .
2584            'VERSION:4.0' . "\n" .
2585            'REV:19951031T222710Z' . "\n" .
2586            'END:VCARD' . "\n"
2587        );
2588
2589    }
2590
2591    /**
2592     * Property: SOUND.
2593     */
2594    function testRFC6350Section6_7_5() {
2595
2596        $this->assertXMLEqualsToMimeDir(
2597<<<XML
2598<?xml version="1.0" encoding="UTF-8"?>
2599<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
2600 <vcard>
2601  <sound>
2602   <uri>CID:JOHNQPUBLIC.part8.19960229T080000.xyzMail@example.com</uri>
2603  </sound>
2604 </vcard>
2605</vcards>
2606XML
2607,
2608            'BEGIN:VCARD' . "\n" .
2609            'VERSION:4.0' . "\n" .
2610            'SOUND:CID:JOHNQPUBLIC.part8.19960229T080000.xyzMail@example.com' . "\n" .
2611            'END:VCARD' . "\n"
2612        );
2613
2614        $this->assertXMLReflexivelyEqualsToMimeDir(
2615<<<XML
2616<?xml version="1.0" encoding="UTF-8"?>
2617<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
2618 <vcard>
2619  <sound>
2620   <text>CID:JOHNQPUBLIC.part8.19960229T080000.xyzMail@example.com</text>
2621  </sound>
2622 </vcard>
2623</vcards>
2624XML
2625,
2626            'BEGIN:VCARD' . "\n" .
2627            'VERSION:4.0' . "\n" .
2628            'SOUND:CID:JOHNQPUBLIC.part8.19960229T080000.xyzMail@example.com' . "\n" .
2629            'END:VCARD' . "\n"
2630        );
2631
2632    }
2633
2634    /**
2635     * Property: UID.
2636     */
2637    function testRFC6350Section6_7_6() {
2638
2639        $this->assertXMLReflexivelyEqualsToMimeDir(
2640<<<XML
2641<?xml version="1.0" encoding="UTF-8"?>
2642<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
2643 <vcard>
2644  <uid>
2645   <text>urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6</text>
2646  </uid>
2647 </vcard>
2648</vcards>
2649XML
2650,
2651            'BEGIN:VCARD' . "\n" .
2652            'VERSION:4.0' . "\n" .
2653            'UID:urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6' . "\n" .
2654            'END:VCARD' . "\n"
2655        );
2656
2657    }
2658
2659    /**
2660     * Property: CLIENTPIDMAP.
2661     */
2662    function testRFC6350Section6_7_7() {
2663
2664        $this->assertXMLReflexivelyEqualsToMimeDir(
2665<<<XML
2666<?xml version="1.0" encoding="UTF-8"?>
2667<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
2668 <vcard>
2669  <clientpidmap>
2670   <sourceid>1</sourceid>
2671   <uri>urn:uuid:3df403f4-5924-4bb7-b077-3c711d9eb34b</uri>
2672  </clientpidmap>
2673 </vcard>
2674</vcards>
2675XML
2676,
2677            'BEGIN:VCARD' . "\n" .
2678            'VERSION:4.0' . "\n" .
2679            'CLIENTPIDMAP:1;urn:uuid:3df403f4-5924-4bb7-b077-3c711d9eb34b' . "\n" .
2680            'END:VCARD' . "\n"
2681        );
2682
2683    }
2684
2685    /**
2686     * Property: URL.
2687     */
2688    function testRFC6350Section6_7_8() {
2689
2690        $this->assertXMLReflexivelyEqualsToMimeDir(
2691<<<XML
2692<?xml version="1.0" encoding="UTF-8"?>
2693<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
2694 <vcard>
2695  <url>
2696   <uri>http://example.org/restaurant.french/~chezchic.html</uri>
2697  </url>
2698 </vcard>
2699</vcards>
2700XML
2701,
2702            'BEGIN:VCARD' . "\n" .
2703            'VERSION:4.0' . "\n" .
2704            'URL:http://example.org/restaurant.french/~chezchic.html' . "\n" .
2705            'END:VCARD' . "\n"
2706        );
2707
2708    }
2709
2710    /**
2711     * Property: VERSION.
2712     */
2713    function testRFC6350Section6_7_9() {
2714
2715        $this->assertXMLReflexivelyEqualsToMimeDir(
2716<<<XML
2717<?xml version="1.0" encoding="UTF-8"?>
2718<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
2719 <vcard/>
2720</vcards>
2721XML
2722,
2723            'BEGIN:VCARD' . "\n" .
2724            'VERSION:4.0' . "\n" .
2725            'END:VCARD' . "\n"
2726        );
2727
2728    }
2729
2730    /**
2731     * Property: KEY.
2732     */
2733    function testRFC6350Section6_8_1() {
2734
2735        $this->assertXMLReflexivelyEqualsToMimeDir(
2736<<<XML
2737<?xml version="1.0" encoding="UTF-8"?>
2738<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
2739 <vcard>
2740  <key>
2741   <parameters>
2742    <mediatype>
2743     <text>application/pgp-keys</text>
2744    </mediatype>
2745   </parameters>
2746   <text>ftp://example.com/keys/jdoe</text>
2747  </key>
2748 </vcard>
2749</vcards>
2750XML
2751,
2752            'BEGIN:VCARD' . "\n" .
2753            'VERSION:4.0' . "\n" .
2754            'KEY;MEDIATYPE=application/pgp-keys:ftp://example.com/keys/jdoe' . "\n" .
2755            'END:VCARD' . "\n"
2756        );
2757
2758    }
2759
2760    /**
2761     * Property: FBURL.
2762     */
2763    function testRFC6350Section6_9_1() {
2764
2765        $this->assertXMLReflexivelyEqualsToMimeDir(
2766<<<XML
2767<?xml version="1.0" encoding="UTF-8"?>
2768<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
2769 <vcard>
2770  <fburl>
2771   <parameters>
2772    <pref>
2773     <text>1</text>
2774    </pref>
2775   </parameters>
2776   <uri>http://www.example.com/busy/janedoe</uri>
2777  </fburl>
2778 </vcard>
2779</vcards>
2780XML
2781,
2782            'BEGIN:VCARD' . "\n" .
2783            'VERSION:4.0' . "\n" .
2784            'FBURL;PREF=1:http://www.example.com/busy/janedoe' . "\n" .
2785            'END:VCARD' . "\n"
2786        );
2787
2788    }
2789
2790    /**
2791     * Property: CALADRURI.
2792     */
2793    function testRFC6350Section6_9_2() {
2794
2795        $this->assertXMLReflexivelyEqualsToMimeDir(
2796<<<XML
2797<?xml version="1.0" encoding="UTF-8"?>
2798<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
2799 <vcard>
2800  <caladruri>
2801   <uri>http://example.com/calendar/jdoe</uri>
2802  </caladruri>
2803 </vcard>
2804</vcards>
2805XML
2806,
2807            'BEGIN:VCARD' . "\n" .
2808            'VERSION:4.0' . "\n" .
2809            'CALADRURI:http://example.com/calendar/jdoe' . "\n" .
2810            'END:VCARD' . "\n"
2811        );
2812
2813    }
2814
2815    /**
2816     * Property: CALURI.
2817     */
2818    function testRFC6350Section6_9_3() {
2819
2820        $this->assertXMLReflexivelyEqualsToMimeDir(
2821<<<XML
2822<?xml version="1.0" encoding="UTF-8"?>
2823<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
2824 <vcard>
2825  <caluri>
2826   <parameters>
2827    <pref>
2828     <text>1</text>
2829    </pref>
2830   </parameters>
2831   <uri>http://cal.example.com/calA</uri>
2832  </caluri>
2833 </vcard>
2834</vcards>
2835XML
2836,
2837            'BEGIN:VCARD' . "\n" .
2838            'VERSION:4.0' . "\n" .
2839            'CALURI;PREF=1:http://cal.example.com/calA' . "\n" .
2840            'END:VCARD' . "\n"
2841        );
2842
2843    }
2844
2845    /**
2846     * Property: CAPURI.
2847     */
2848    function testRFC6350SectionA_3() {
2849
2850        $this->assertXMLReflexivelyEqualsToMimeDir(
2851<<<XML
2852<?xml version="1.0" encoding="UTF-8"?>
2853<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
2854 <vcard>
2855  <capuri>
2856   <uri>http://cap.example.com/capA</uri>
2857  </capuri>
2858 </vcard>
2859</vcards>
2860XML
2861,
2862            'BEGIN:VCARD' . "\n" .
2863            'VERSION:4.0' . "\n" .
2864            'CAPURI:http://cap.example.com/capA' . "\n" .
2865            'END:VCARD' . "\n"
2866        );
2867
2868    }
2869
2870    /**
2871     * Check this equality:
2872     *     XML -> object model -> MIME Dir.
2873     */
2874    protected function assertXMLEqualsToMimeDir($xml, $mimedir) {
2875
2876        $component = VObject\Reader::readXML($xml);
2877        $this->assertVObjectEqualsVObject($mimedir, $component);
2878
2879    }
2880
2881    /**
2882     * Check this (reflexive) equality:
2883     *     XML -> object model -> MIME Dir -> object model -> XML.
2884     */
2885    protected function assertXMLReflexivelyEqualsToMimeDir($xml, $mimedir) {
2886
2887        $this->assertXMLEqualsToMimeDir($xml, $mimedir);
2888
2889        $component = VObject\Reader::read($mimedir);
2890        $this->assertXmlStringEqualsXmlString($xml, VObject\Writer::writeXML($component));
2891
2892    }
2893}
2894