698 lines
13 KiB
PHP
698 lines
13 KiB
PHP
<?php
|
|
|
|
namespace Sabre\VObject\Component;
|
|
|
|
use DateTimeZone;
|
|
use Sabre\VObject;
|
|
|
|
class VCalendarTest extends \PHPUnit_Framework_TestCase {
|
|
|
|
/**
|
|
* @dataProvider expandData
|
|
*/
|
|
public function testExpand($input, $output, $timeZone = 'UTC', $start = '2011-12-01', $end = '2011-12-31') {
|
|
|
|
$vcal = VObject\Reader::read($input);
|
|
|
|
$timeZone = new DateTimeZone($timeZone);
|
|
|
|
$vcal->expand(
|
|
new \DateTime($start),
|
|
new \DateTime($end),
|
|
$timeZone
|
|
);
|
|
|
|
// This will normalize the output
|
|
$output = VObject\Reader::read($output)->serialize();
|
|
|
|
$this->assertEquals($output, $vcal->serialize());
|
|
|
|
}
|
|
|
|
public function expandData() {
|
|
|
|
$tests = array();
|
|
|
|
// No data
|
|
$input = 'BEGIN:VCALENDAR
|
|
CALSCALE:GREGORIAN
|
|
VERSION:2.0
|
|
END:VCALENDAR
|
|
';
|
|
|
|
$output = $input;
|
|
$tests[] = array($input,$output);
|
|
|
|
|
|
// Simple events
|
|
$input = 'BEGIN:VCALENDAR
|
|
CALSCALE:GREGORIAN
|
|
VERSION:2.0
|
|
BEGIN:VEVENT
|
|
UID:bla
|
|
SUMMARY:InExpand
|
|
DTSTART;VALUE=DATE:20111202
|
|
END:VEVENT
|
|
BEGIN:VEVENT
|
|
UID:bla2
|
|
SUMMARY:NotInExpand
|
|
DTSTART;VALUE=DATE:20120101
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
';
|
|
|
|
$output = 'BEGIN:VCALENDAR
|
|
CALSCALE:GREGORIAN
|
|
VERSION:2.0
|
|
BEGIN:VEVENT
|
|
UID:bla
|
|
SUMMARY:InExpand
|
|
DTSTART;VALUE=DATE:20111202
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
';
|
|
|
|
$tests[] = array($input, $output);
|
|
|
|
// Removing timezone info
|
|
$input = 'BEGIN:VCALENDAR
|
|
CALSCALE:GREGORIAN
|
|
VERSION:2.0
|
|
BEGIN:VTIMEZONE
|
|
TZID:Europe/Paris
|
|
END:VTIMEZONE
|
|
BEGIN:VEVENT
|
|
UID:bla4
|
|
SUMMARY:RemoveTZ info
|
|
DTSTART;TZID=Europe/Paris:20111203T130102
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
';
|
|
|
|
$output = 'BEGIN:VCALENDAR
|
|
CALSCALE:GREGORIAN
|
|
VERSION:2.0
|
|
BEGIN:VEVENT
|
|
UID:bla4
|
|
SUMMARY:RemoveTZ info
|
|
DTSTART:20111203T120102Z
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
';
|
|
|
|
$tests[] = array($input, $output);
|
|
|
|
// Recurrence rule
|
|
$input = 'BEGIN:VCALENDAR
|
|
CALSCALE:GREGORIAN
|
|
VERSION:2.0
|
|
BEGIN:VEVENT
|
|
UID:bla6
|
|
SUMMARY:Testing RRule
|
|
DTSTART:20111125T120000Z
|
|
DTEND:20111125T130000Z
|
|
RRULE:FREQ=WEEKLY
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
';
|
|
|
|
$output = 'BEGIN:VCALENDAR
|
|
CALSCALE:GREGORIAN
|
|
VERSION:2.0
|
|
BEGIN:VEVENT
|
|
UID:bla6
|
|
SUMMARY:Testing RRule
|
|
DTSTART:20111202T120000Z
|
|
DTEND:20111202T130000Z
|
|
RECURRENCE-ID:20111202T120000Z
|
|
END:VEVENT
|
|
BEGIN:VEVENT
|
|
UID:bla6
|
|
SUMMARY:Testing RRule
|
|
DTSTART:20111209T120000Z
|
|
DTEND:20111209T130000Z
|
|
RECURRENCE-ID:20111209T120000Z
|
|
END:VEVENT
|
|
BEGIN:VEVENT
|
|
UID:bla6
|
|
SUMMARY:Testing RRule
|
|
DTSTART:20111216T120000Z
|
|
DTEND:20111216T130000Z
|
|
RECURRENCE-ID:20111216T120000Z
|
|
END:VEVENT
|
|
BEGIN:VEVENT
|
|
UID:bla6
|
|
SUMMARY:Testing RRule
|
|
DTSTART:20111223T120000Z
|
|
DTEND:20111223T130000Z
|
|
RECURRENCE-ID:20111223T120000Z
|
|
END:VEVENT
|
|
BEGIN:VEVENT
|
|
UID:bla6
|
|
SUMMARY:Testing RRule
|
|
DTSTART:20111230T120000Z
|
|
DTEND:20111230T130000Z
|
|
RECURRENCE-ID:20111230T120000Z
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
';
|
|
|
|
$tests[] = array($input, $output);
|
|
|
|
// Recurrence rule + override
|
|
$input = 'BEGIN:VCALENDAR
|
|
CALSCALE:GREGORIAN
|
|
VERSION:2.0
|
|
BEGIN:VEVENT
|
|
UID:bla6
|
|
SUMMARY:Testing RRule2
|
|
DTSTART:20111125T120000Z
|
|
DTEND:20111125T130000Z
|
|
RRULE:FREQ=WEEKLY
|
|
END:VEVENT
|
|
BEGIN:VEVENT
|
|
UID:bla6
|
|
RECURRENCE-ID:20111209T120000Z
|
|
DTSTART:20111209T140000Z
|
|
DTEND:20111209T150000Z
|
|
SUMMARY:Override!
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
';
|
|
|
|
$output = 'BEGIN:VCALENDAR
|
|
CALSCALE:GREGORIAN
|
|
VERSION:2.0
|
|
BEGIN:VEVENT
|
|
UID:bla6
|
|
SUMMARY:Testing RRule2
|
|
DTSTART:20111202T120000Z
|
|
DTEND:20111202T130000Z
|
|
RECURRENCE-ID:20111202T120000Z
|
|
END:VEVENT
|
|
BEGIN:VEVENT
|
|
UID:bla6
|
|
RECURRENCE-ID:20111209T120000Z
|
|
DTSTART:20111209T140000Z
|
|
DTEND:20111209T150000Z
|
|
SUMMARY:Override!
|
|
END:VEVENT
|
|
BEGIN:VEVENT
|
|
UID:bla6
|
|
SUMMARY:Testing RRule2
|
|
DTSTART:20111216T120000Z
|
|
DTEND:20111216T130000Z
|
|
RECURRENCE-ID:20111216T120000Z
|
|
END:VEVENT
|
|
BEGIN:VEVENT
|
|
UID:bla6
|
|
SUMMARY:Testing RRule2
|
|
DTSTART:20111223T120000Z
|
|
DTEND:20111223T130000Z
|
|
RECURRENCE-ID:20111223T120000Z
|
|
END:VEVENT
|
|
BEGIN:VEVENT
|
|
UID:bla6
|
|
SUMMARY:Testing RRule2
|
|
DTSTART:20111230T120000Z
|
|
DTEND:20111230T130000Z
|
|
RECURRENCE-ID:20111230T120000Z
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
';
|
|
|
|
$tests[] = array($input, $output);
|
|
|
|
// Floating dates and times.
|
|
$input = <<<ICS
|
|
BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
BEGIN:VEVENT
|
|
UID:bla1
|
|
DTSTART:20141112T195000
|
|
END:VEVENT
|
|
BEGIN:VEVENT
|
|
UID:bla2
|
|
DTSTART;VALUE=DATE:20141112
|
|
END:VEVENT
|
|
BEGIN:VEVENT
|
|
UID:bla3
|
|
DTSTART;VALUE=DATE:20141112
|
|
RRULE:FREQ=DAILY;COUNT=2
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
ICS;
|
|
|
|
$output = <<<ICS
|
|
BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
BEGIN:VEVENT
|
|
UID:bla1
|
|
DTSTART:20141112T225000Z
|
|
END:VEVENT
|
|
BEGIN:VEVENT
|
|
UID:bla2
|
|
DTSTART;VALUE=DATE:20141112
|
|
END:VEVENT
|
|
BEGIN:VEVENT
|
|
UID:bla3
|
|
DTSTART;VALUE=DATE:20141112
|
|
RECURRENCE-ID;VALUE=DATE:20141112
|
|
END:VEVENT
|
|
BEGIN:VEVENT
|
|
UID:bla3
|
|
DTSTART;VALUE=DATE:20141113
|
|
RECURRENCE-ID;VALUE=DATE:20141113
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
ICS;
|
|
|
|
$tests[] = array($input, $output, 'America/Argentina/Buenos_Aires', '2014-01-01', '2015-01-01');
|
|
|
|
// Recurrence rule with no valid instances
|
|
$input = 'BEGIN:VCALENDAR
|
|
CALSCALE:GREGORIAN
|
|
VERSION:2.0
|
|
BEGIN:VEVENT
|
|
UID:bla6
|
|
SUMMARY:Testing RRule3
|
|
DTSTART:20111125T120000Z
|
|
DTEND:20111125T130000Z
|
|
RRULE:FREQ=WEEKLY;COUNT=1
|
|
EXDATE:20111125T120000Z
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
';
|
|
|
|
$output = 'BEGIN:VCALENDAR
|
|
CALSCALE:GREGORIAN
|
|
VERSION:2.0
|
|
END:VCALENDAR
|
|
';
|
|
|
|
$tests[] = array($input, $output);
|
|
return $tests;
|
|
|
|
}
|
|
|
|
/**
|
|
* @expectedException LogicException
|
|
*/
|
|
public function testBrokenEventExpand() {
|
|
|
|
$input = 'BEGIN:VCALENDAR
|
|
CALSCALE:GREGORIAN
|
|
VERSION:2.0
|
|
BEGIN:VEVENT
|
|
RRULE:FREQ=WEEKLY
|
|
DTSTART;VALUE=DATE:20111202
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
';
|
|
$vcal = VObject\Reader::read($input);
|
|
$vcal->expand(
|
|
new \DateTime('2011-12-01'),
|
|
new \DateTime('2011-12-31')
|
|
);
|
|
|
|
}
|
|
|
|
function testGetDocumentType() {
|
|
|
|
$vcard = new VCalendar();
|
|
$vcard->VERSION = '2.0';
|
|
$this->assertEquals(VCalendar::ICALENDAR20, $vcard->getDocumentType());
|
|
|
|
}
|
|
|
|
function testValidateCorrect() {
|
|
|
|
$input = 'BEGIN:VCALENDAR
|
|
CALSCALE:GREGORIAN
|
|
VERSION:2.0
|
|
PRODID:foo
|
|
BEGIN:VEVENT
|
|
DTSTART;VALUE=DATE:20111202
|
|
DTSTAMP:20140122T233226Z
|
|
UID:foo
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
';
|
|
|
|
$vcal = VObject\Reader::read($input);
|
|
$this->assertEquals(array(), $vcal->validate(), 'Got an error');
|
|
|
|
}
|
|
|
|
function testValidateNoVersion() {
|
|
|
|
$input = 'BEGIN:VCALENDAR
|
|
CALSCALE:GREGORIAN
|
|
PRODID:foo
|
|
BEGIN:VEVENT
|
|
DTSTART;VALUE=DATE:20111202
|
|
UID:foo
|
|
DTSTAMP:20140122T234434Z
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
';
|
|
|
|
$vcal = VObject\Reader::read($input);
|
|
$this->assertEquals(1, count($vcal->validate()));
|
|
|
|
}
|
|
|
|
function testValidateWrongVersion() {
|
|
|
|
$input = 'BEGIN:VCALENDAR
|
|
CALSCALE:GREGORIAN
|
|
VERSION:3.0
|
|
PRODID:foo
|
|
BEGIN:VEVENT
|
|
DTSTART;VALUE=DATE:20111202
|
|
UID:foo
|
|
DTSTAMP:20140122T234434Z
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
';
|
|
|
|
$vcal = VObject\Reader::read($input);
|
|
$this->assertEquals(1, count($vcal->validate()));
|
|
|
|
}
|
|
|
|
function testValidateNoProdId() {
|
|
|
|
$input = 'BEGIN:VCALENDAR
|
|
CALSCALE:GREGORIAN
|
|
VERSION:2.0
|
|
BEGIN:VEVENT
|
|
DTSTART;VALUE=DATE:20111202
|
|
UID:foo
|
|
DTSTAMP:20140122T234434Z
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
';
|
|
|
|
$vcal = VObject\Reader::read($input);
|
|
$this->assertEquals(1, count($vcal->validate()));
|
|
|
|
}
|
|
|
|
function testValidateDoubleCalScale() {
|
|
|
|
$input = 'BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
PRODID:foo
|
|
CALSCALE:GREGORIAN
|
|
CALSCALE:GREGORIAN
|
|
BEGIN:VEVENT
|
|
DTSTART;VALUE=DATE:20111202
|
|
UID:foo
|
|
DTSTAMP:20140122T234434Z
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
';
|
|
|
|
$vcal = VObject\Reader::read($input);
|
|
$this->assertEquals(1, count($vcal->validate()));
|
|
|
|
}
|
|
|
|
function testValidateDoubleMethod() {
|
|
|
|
$input = 'BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
PRODID:foo
|
|
METHOD:REQUEST
|
|
METHOD:REQUEST
|
|
BEGIN:VEVENT
|
|
DTSTART;VALUE=DATE:20111202
|
|
UID:foo
|
|
DTSTAMP:20140122T234434Z
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
';
|
|
|
|
$vcal = VObject\Reader::read($input);
|
|
$this->assertEquals(1, count($vcal->validate()));
|
|
|
|
}
|
|
|
|
function testValidateTwoMasterEvents() {
|
|
|
|
$input = 'BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
PRODID:foo
|
|
METHOD:REQUEST
|
|
BEGIN:VEVENT
|
|
DTSTART;VALUE=DATE:20111202
|
|
UID:foo
|
|
DTSTAMP:20140122T234434Z
|
|
END:VEVENT
|
|
BEGIN:VEVENT
|
|
DTSTART;VALUE=DATE:20111202
|
|
UID:foo
|
|
DTSTAMP:20140122T234434Z
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
';
|
|
|
|
$vcal = VObject\Reader::read($input);
|
|
$this->assertEquals(1, count($vcal->validate()));
|
|
|
|
}
|
|
|
|
function testValidateOneMasterEvent() {
|
|
|
|
$input = 'BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
PRODID:foo
|
|
METHOD:REQUEST
|
|
BEGIN:VEVENT
|
|
DTSTART;VALUE=DATE:20111202
|
|
UID:foo
|
|
DTSTAMP:20140122T234434Z
|
|
END:VEVENT
|
|
BEGIN:VEVENT
|
|
DTSTART;VALUE=DATE:20111202
|
|
UID:foo
|
|
DTSTAMP:20140122T234434Z
|
|
RECURRENCE-ID;VALUE=DATE:20111202
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
';
|
|
|
|
$vcal = VObject\Reader::read($input);
|
|
$this->assertEquals(0, count($vcal->validate()));
|
|
|
|
}
|
|
|
|
function testGetBaseComponent() {
|
|
|
|
$input = 'BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
PRODID:foo
|
|
METHOD:REQUEST
|
|
BEGIN:VEVENT
|
|
SUMMARY:test
|
|
DTSTART;VALUE=DATE:20111202
|
|
UID:foo
|
|
DTSTAMP:20140122T234434Z
|
|
END:VEVENT
|
|
BEGIN:VEVENT
|
|
DTSTART;VALUE=DATE:20111202
|
|
UID:foo
|
|
DTSTAMP:20140122T234434Z
|
|
RECURRENCE-ID;VALUE=DATE:20111202
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
';
|
|
|
|
$vcal = VObject\Reader::read($input);
|
|
|
|
$result = $vcal->getBaseComponent();
|
|
$this->assertEquals('test', $result->SUMMARY->getValue());
|
|
|
|
}
|
|
|
|
function testGetBaseComponentNoResult() {
|
|
|
|
$input = 'BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
PRODID:foo
|
|
METHOD:REQUEST
|
|
BEGIN:VEVENT
|
|
SUMMARY:test
|
|
RECURRENCE-ID;VALUE=DATE:20111202
|
|
DTSTART;VALUE=DATE:20111202
|
|
UID:foo
|
|
DTSTAMP:20140122T234434Z
|
|
END:VEVENT
|
|
BEGIN:VEVENT
|
|
DTSTART;VALUE=DATE:20111202
|
|
UID:foo
|
|
DTSTAMP:20140122T234434Z
|
|
RECURRENCE-ID;VALUE=DATE:20111202
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
';
|
|
|
|
$vcal = VObject\Reader::read($input);
|
|
|
|
$result = $vcal->getBaseComponent();
|
|
$this->assertNull($result);
|
|
|
|
}
|
|
|
|
function testNoComponents() {
|
|
|
|
$input = <<<ICS
|
|
BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
PRODID:vobject
|
|
END:VCALENDAR
|
|
ICS;
|
|
|
|
$this->assertValidate(
|
|
$input,
|
|
0,
|
|
3,
|
|
"An iCalendar object must have at least 1 component."
|
|
);
|
|
|
|
}
|
|
|
|
function testCalDAVNoComponents() {
|
|
|
|
$input = <<<ICS
|
|
BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
PRODID:vobject
|
|
BEGIN:VTIMEZONE
|
|
TZID:America/Toronto
|
|
END:VTIMEZONE
|
|
END:VCALENDAR
|
|
ICS;
|
|
|
|
$this->assertValidate(
|
|
$input,
|
|
VCalendar::PROFILE_CALDAV,
|
|
3,
|
|
"A calendar object on a CalDAV server must have at least 1 component (VTODO, VEVENT, VJOURNAL)."
|
|
);
|
|
|
|
}
|
|
|
|
function testCalDAVMultiUID() {
|
|
|
|
$input = <<<ICS
|
|
BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
PRODID:vobject
|
|
BEGIN:VEVENT
|
|
UID:foo
|
|
DTSTAMP:20150109T184500Z
|
|
DTSTART:20150109T184500Z
|
|
END:VEVENT
|
|
BEGIN:VEVENT
|
|
UID:bar
|
|
DTSTAMP:20150109T184500Z
|
|
DTSTART:20150109T184500Z
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
ICS;
|
|
|
|
$this->assertValidate(
|
|
$input,
|
|
VCalendar::PROFILE_CALDAV,
|
|
3,
|
|
"A calendar object on a CalDAV server may only have components with the same UID."
|
|
);
|
|
|
|
}
|
|
|
|
function testCalDAVMultiComponent() {
|
|
|
|
$input = <<<ICS
|
|
BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
PRODID:vobject
|
|
BEGIN:VEVENT
|
|
UID:foo
|
|
RECURRENCE-ID:20150109T185200Z
|
|
DTSTAMP:20150109T184500Z
|
|
DTSTART:20150109T184500Z
|
|
END:VEVENT
|
|
BEGIN:VTODO
|
|
UID:foo
|
|
DTSTAMP:20150109T184500Z
|
|
DTSTART:20150109T184500Z
|
|
END:VTODO
|
|
END:VCALENDAR
|
|
ICS;
|
|
|
|
$this->assertValidate(
|
|
$input,
|
|
VCalendar::PROFILE_CALDAV,
|
|
3,
|
|
"A calendar object on a CalDAV server may only have 1 type of component (VEVENT, VTODO or VJOURNAL)."
|
|
);
|
|
|
|
}
|
|
|
|
function testCalDAVMETHOD() {
|
|
|
|
$input = <<<ICS
|
|
BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
METHOD:PUBLISH
|
|
PRODID:vobject
|
|
BEGIN:VEVENT
|
|
UID:foo
|
|
RECURRENCE-ID:20150109T185200Z
|
|
DTSTAMP:20150109T184500Z
|
|
DTSTART:20150109T184500Z
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
ICS;
|
|
|
|
$this->assertValidate(
|
|
$input,
|
|
VCalendar::PROFILE_CALDAV,
|
|
3,
|
|
"A calendar object on a CalDAV server MUST NOT have a METHOD property."
|
|
);
|
|
|
|
}
|
|
|
|
function assertValidate($ics, $options, $expectedLevel, $expectedMessage = null) {
|
|
|
|
$vcal = VObject\Reader::read($ics);
|
|
$result = $vcal->validate($options);
|
|
|
|
$this->assertValidateResult($result, $expectedLevel, $expectedMessage);
|
|
|
|
}
|
|
|
|
function assertValidateResult($input, $expectedLevel, $expectedMessage = null) {
|
|
|
|
$messages = array();
|
|
foreach($input as $warning) {
|
|
$messages[] = $warning['message'];
|
|
}
|
|
|
|
if ($expectedLevel === 0) {
|
|
$this->assertEquals(0, count($input), 'No validation messages were expected. We got: ' . implode(', ', $messages));
|
|
} else {
|
|
$this->assertEquals(1, count($input), 'We expected exactly 1 validation message, We got: ' . implode(', ', $messages));
|
|
|
|
$this->assertEquals($expectedMessage, $input[0]['message']);
|
|
$this->assertEquals($expectedLevel, $input[0]['level']);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
}
|