From 5b5f395feb19fd4cc456b5f20f36efc8c8bf2a56 Mon Sep 17 00:00:00 2001 From: Gunnar Wrobel Date: Fri, 6 Aug 2010 22:41:54 +0200 Subject: [PATCH] Added testing and fixed some initial problems. --- framework/Itip/lib/Horde/Itip/Event/Vevent.php | 42 ++-- framework/Itip/lib/Horde/Itip/Response.php | 48 ++-- framework/Itip/package.xml | 140 +++++++++++ framework/Itip/test/Horde/Itip/AllTests.php | 45 ++++ framework/Itip/test/Horde/Itip/Autoload.php | 29 +++ .../Itip/test/Horde/Itip/Integration/ItipTest.php | 256 +++++++++++++++++++++ framework/Itip/test/Horde/Itip/phpunit.xml | 8 + 7 files changed, 516 insertions(+), 52 deletions(-) create mode 100644 framework/Itip/package.xml create mode 100644 framework/Itip/test/Horde/Itip/AllTests.php create mode 100644 framework/Itip/test/Horde/Itip/Autoload.php create mode 100644 framework/Itip/test/Horde/Itip/Integration/ItipTest.php create mode 100644 framework/Itip/test/Horde/Itip/phpunit.xml diff --git a/framework/Itip/lib/Horde/Itip/Event/Vevent.php b/framework/Itip/lib/Horde/Itip/Event/Vevent.php index f5741b081..fdf2fd33e 100644 --- a/framework/Itip/lib/Horde/Itip/Event/Vevent.php +++ b/framework/Itip/lib/Horde/Itip/Event/Vevent.php @@ -14,7 +14,8 @@ /** * A wrapper for vEvent iCalender data. * - * Copyright 2010 Klarälvdalens Datakonsult AB + * Copyright 2002-2010 The Horde Project (http://www.horde.org/) + * Copyright 2004-2010 Klarälvdalens Datakonsult AB * * See the enclosed file COPYING for license information (LGPL). If you did not * receive this file, see @@ -388,7 +389,8 @@ implements Horde_Itip_Event */ public function getStartParameters() { - return array_pop($this->_vevent->getAttribute('DTSTART', true)); + $parameters = $this->_vevent->getAttribute('DTSTART', true); + return array_pop($parameters); } /** @@ -415,23 +417,14 @@ implements Horde_Itip_Event } /** - * Does the event have an end? - * - * @return boolean True if it has an end, false otherwise. - */ - private function hasEnd() - { - return !($this->_vevent->getAttribute('DTEND') instanceOf PEAR_Error); - } - - /** * Return the end parameters of the iTip event. * * @return array The end parameters of the event. */ private function getEndParameters() { - return array_pop($this->_vevent->getAttribute('DTEND', true)); + $parameters = $this->_vevent->getAttribute('DTEND', true); + return array_pop($parameters); } /** @@ -464,7 +457,8 @@ implements Horde_Itip_Event */ private function getDurationParameters() { - return array_pop($this->_vevent->getAttribute('DURATION', true)); + $parameters = $this->_vevent->getAttribute('DURATION', true); + return array_pop($parameters); } /** @@ -488,9 +482,9 @@ implements Horde_Itip_Event */ private function copyEndOrDuration(Horde_Itip_Event $itip) { - if ($this->hasEnd()) { + try { $itip->setEnd($this->getEnd(), $this->getEndParameters()); - } else { + } catch (Horde_Icalendar_Exception $e) { $itip->setDuration($this->getDuration(), $this->getDurationParameters()); } } @@ -527,16 +521,6 @@ implements Horde_Itip_Event } /** - * Does the event have a location? - * - * @return boolean True if it has a location, false otherwise. - */ - private function hasLocation() - { - return !($this->_vevent->getAttribute('LOCATION') instanceOf PEAR_Error); - } - - /** * Return the location for the event. * * @return string|PEAR_Error The location. @@ -565,8 +549,9 @@ implements Horde_Itip_Event */ private function copyLocation(Horde_Itip_Event $itip) { - if ($this->hasLocation()) { + try { $itip->setLocation($this->getLocation()); + } catch (Horde_Icalendar_Exception $e) { } } @@ -587,7 +572,8 @@ implements Horde_Itip_Event */ private function getOrganizerParameters() { - return array_pop($this->_vevent->getAttribute('ORGANIZER', true)); + $parameters = $this->_vevent->getAttribute('ORGANIZER', true); + return array_pop($parameters); } /** diff --git a/framework/Itip/lib/Horde/Itip/Response.php b/framework/Itip/lib/Horde/Itip/Response.php index 3fea90c41..6827ecb3b 100644 --- a/framework/Itip/lib/Horde/Itip/Response.php +++ b/framework/Itip/lib/Horde/Itip/Response.php @@ -6,6 +6,8 @@ * * @category Horde * @package Itip + * @author Mike Cochrane + * @author Chuck Hagenbuch * @author Steffen Hansen * @author Gunnar Wrobel * @license http://www.fsf.org/copyleft/lgpl.html LGPL @@ -15,6 +17,7 @@ /** * Handles Itip response data. * + * Copyright 2002-2010 The Horde Project (http://www.horde.org/) * Copyright 2004-2010 Klarälvdalens Datakonsult AB * * See the enclosed file COPYING for license information (LGPL). If you did not @@ -23,6 +26,8 @@ * * @category Horde * @package Itip + * @author Mike Cochrane + * @author Chuck Hagenbuch * @author Steffen Hansen * @author Gunnar Wrobel * @license http://www.fsf.org/copyleft/lgpl.html LGPL @@ -54,11 +59,9 @@ class Horde_Itip_Response /** * Constructor. * - * @param Horde_Itip_Event $request The request this - * instance will respond - * to. - * @param Horde_Itip_Resource $resource The requested - * resource. + * @param Horde_Itip_Event $request The request this instance will + * respond to. + * @param Horde_Itip_Resource $resource The requested resource. */ public function __construct( Horde_Itip_Event $request, @@ -69,7 +72,7 @@ class Horde_Itip_Response } /** - * Return the response as an iCalendar vveEnt object. + * Return the response as an iCalendar vEvent object. * * @param Horde_Itip_Response_Type $type The response type. * @param Horde_iCalendar|boolean $vCal The parent container or false if not @@ -99,12 +102,9 @@ class Horde_Itip_Response /** * Return the response as an iCalendar object. * - * @param Horde_Itip_Response_Type $type The response - * type. - * @param string $product_id The ID that - * should be set - * as the iCalendar - * product id. + * @param Horde_Itip_Response_Type $type The response type. + * @param string $product_id The ID that should be set as + * the iCalendar product id. * * @return Horde_iCalendar The response object. */ @@ -122,13 +122,12 @@ class Horde_Itip_Response /** * Return the response as a MIME message. * - * @param Horde_Itip_Response_Type $type The response - * type. - * @param string $product_id The ID that - * should be set - * as the iCalendar - * product id. - * @param string $subject_comment An optional comment on the subject line. + * @param Horde_Itip_Response_Type $type The response type. + * @param string $product_id The ID that should be set + * as the iCalendar product + * id. + * @param string $subject_comment An optional comment on + * the subject line. * * @return array A list of two object: The mime headers and the mime * message. @@ -138,10 +137,11 @@ class Horde_Itip_Response $product_id, $subject_comment = null ) { - $ics = new MIME_Part( - 'text/calendar', - $this->getIcalendar($type, $product_id)->exportvCalendar(), - 'UTF-8' + $ics = new Horde_Mime_Part(); + $ics->setType('text/calendar'); + $ics->setCharset('UTF-8'); + $ics->setContents( + $this->getIcalendar($type, $product_id)->exportvCalendar() ); $ics->setContentTypeParameter('method', 'REPLY'); @@ -153,7 +153,7 @@ class Horde_Itip_Response // is so that Outlook interprets the messages as it does Outlook-generated // responses, i.e. double-clicking a reply will automatically update your // meetings, showing different status icons in the UI, etc. - $message = MIME_Message::convertMimePart($ics); + //$message = Horde_Mime_Message::convertMimePart($ics); $message->setCharset('UTF-8'); $message->setTransferEncoding('quoted-printable'); $message->transferEncodeContents(); diff --git a/framework/Itip/package.xml b/framework/Itip/package.xml new file mode 100644 index 000000000..e92eaa8ea --- /dev/null +++ b/framework/Itip/package.xml @@ -0,0 +1,140 @@ + + + Itip + pear.horde.org + iTip invitation response handling. + This package allows to generate MIME encapsuled + responses to iCalender invitations. + + Gunnar Wrobel + wrobel + p@rdus.de + yes + + + Chuck Hagenbuch + chuck + chuck@horde.org + yes + + + Jan Schneider + jan + jan@horde.org + yes + + 2010-08-06 + + + 0.1.0 + 0.1.0 + + + alpha + alpha + + LGPL + +* Extracted package from Kolab_Resource. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5.0.0 + + + 1.4.0b1 + + + Icalendar + pear.horde.org + 0.2.0 + + + Mime + pear.horde.org + 0.1.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + 0.1.0 + 0.1.0 + + + alpha + alpha + + 2010-08-06 + LGPL + +* Extracted package from Kolab_Resource. + + + + diff --git a/framework/Itip/test/Horde/Itip/AllTests.php b/framework/Itip/test/Horde/Itip/AllTests.php new file mode 100644 index 000000000..93a708a7f --- /dev/null +++ b/framework/Itip/test/Horde/Itip/AllTests.php @@ -0,0 +1,45 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Itip + */ + +/** + * Define the main method + */ +if (!defined('PHPUnit_MAIN_METHOD')) { + define('PHPUnit_MAIN_METHOD', 'Horde_Itip_AllTests::main'); +} + +/** + * Prepare the test setup. + */ +require_once 'Horde/Test/AllTests.php'; + +/** + * All tests for the Itip:: package. + * + * @category Horde + * @package Itip + * @subpackage UnitTests + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Itip + */ +class Horde_Itip_AllTests extends Horde_Test_AllTests +{ +} + +Horde_Itip_AllTests::init('Horde_Itip', __FILE__); + +if (PHPUnit_MAIN_METHOD == 'Horde_Itip_AllTests::main') { + Horde_Itip_AllTests::main(); +} diff --git a/framework/Itip/test/Horde/Itip/Autoload.php b/framework/Itip/test/Horde/Itip/Autoload.php new file mode 100644 index 000000000..bd9840f5d --- /dev/null +++ b/framework/Itip/test/Horde/Itip/Autoload.php @@ -0,0 +1,29 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Itip + */ + +if (!spl_autoload_functions()) { + spl_autoload_register( + create_function( + '$class', + '$filename = str_replace(array(\'::\', \'_\'), \'/\', $class);' + . '$err_mask = E_ALL ^ E_WARNING;' + . '$oldErrorReporting = error_reporting($err_mask);' + . 'include "$filename.php";' + . 'error_reporting($oldErrorReporting);' + ) + ); +} + +/** Catch strict standards */ +error_reporting(E_ALL | E_STRICT); diff --git a/framework/Itip/test/Horde/Itip/Integration/ItipTest.php b/framework/Itip/test/Horde/Itip/Integration/ItipTest.php new file mode 100644 index 000000000..5a025dd6d --- /dev/null +++ b/framework/Itip/test/Horde/Itip/Integration/ItipTest.php @@ -0,0 +1,256 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Itip + */ + +/** + * Prepare the test setup. + */ +require_once dirname(__FILE__) . '/../Autoload.php'; + +/** + * Test the itip response handling. + * + * Copyright 2010 Klarälvdalens Datakonsult AB + * + * See the enclosed file COPYING for license information (LGPL). If you did not + * receive this file, see + * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + * + * @category Horde + * @package Itip + * @subpackage UnitTests + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Itip + */ +class Horde_Itip_Integration_ItipTest +extends PHPUnit_Framework_TestCase +{ + public function testMinimalItipHandlingSteps() + { + $iTip = $this->_getItip(); + $reply = $iTip->getVeventResponse( + new Horde_Itip_Response_Type_Accept() + ); + $this->assertEquals($reply->getAttribute('ATTENDEE'), 'MAILTO:test@example.org'); + } + + public function testDefaultSequenceIdSetToZero() + { + $iTip = $this->_getItip(); + $reply = $iTip->getVeventResponse( + new Horde_Itip_Response_Type_Accept() + ); + $this->assertSame($reply->getAttribute('SEQUENCE'), 0); + } + + public function testForCopiedSequenceIdFromRequestToResponse() + { + $inv = $this->_getInvitation(); + $inv->setAttribute('SEQUENCE', 555); + $iTip = $this->_getItip($inv); + $reply = $iTip->getVeventResponse( + new Horde_Itip_Response_Type_Accept() + ); + $this->assertSame($reply->getAttribute('SEQUENCE'), 555); + } + + public function testForCopiedStartTimeFromRequestToResponse() + { + $iTip = $this->_getItip(); + $reply = $iTip->getVeventResponse( + new Horde_Itip_Response_Type_Accept() + ); + $this->assertSame($reply->getAttribute('DTSTART'), array('20080926T110000')); + } + + public function testForCopiedEndTimeFromRequestToResponse() + { + $iTip = $this->_getItip(); + $reply = $iTip->getVeventResponse( + new Horde_Itip_Response_Type_Accept() + ); + $this->assertSame($reply->getAttribute('DTEND'), array('20080926T120000')); + } + + public function testForCopiedDurationFromRequestToResponse() + { + $vCal = new Horde_iCalendar(); + $inv = Horde_iCalendar::newComponent('VEVENT', $vCal); + $inv->setAttribute('METHOD', 'REQUEST'); + $inv->setAttribute('UID', '1'); + $inv->setAttribute('SUMMARY', 'Test Invitation'); + $inv->setAttribute('DESCRIPTION', 'You are invited'); + $inv->setAttribute('ORGANIZER', 'orga@example.org'); + $inv->setAttribute('DTSTART', '20080926T110000'); + $inv->setAttribute('DURATION', 3600); + $iTip = $this->_getItip($inv); + $reply = $iTip->getVeventResponse( + new Horde_Itip_Response_Type_Accept() + ); + $this->assertSame($reply->getAttribute('DURATION'), 3600); + } + + public function testForCopiedOrganizerFromRequestToResponse() + { + $iTip = $this->_getItip(); + $reply = $iTip->getVeventResponse( + new Horde_Itip_Response_Type_Accept() + ); + $this->assertSame($reply->getAttribute('ORGANIZER'), 'orga@example.org'); + } + + public function testForCopiedUidFromRequestToResponse() + { + $iTip = $this->_getItip(); + $reply = $iTip->getVeventResponse( + new Horde_Itip_Response_Type_Accept() + ); + $this->assertSame($reply->getAttribute('UID'), '1'); + } + + public function testIcalendarResponseHasMethodReply() + { + $iTip = $this->_getItip(); + $reply = $iTip->getIcalendarResponse( + new Horde_Itip_Response_Type_Accept(), '' + ); + $this->assertEquals($reply->getAttribute('METHOD'), 'REPLY'); + } + + public function testIcalendarResponseAllowsSettingTheProductId() + { + $iTip = $this->_getItip(); + $reply = $iTip->getIcalendarResponse( + new Horde_Itip_Response_Type_Accept(), 'My product' + ); + $this->assertEquals($reply->getAttribute('PRODID'), 'My product'); + } + + public function testMessageResponseHasFromAddress() + { + $_SERVER['SERVER_NAME'] = 'localhost'; + $iTip = $this->_getItip(); + $reply = $iTip->getMessageResponse( + new Horde_Itip_Response_Type_Accept(), '', '' + ); + + $this->assertContains('From: Mister Test ', $reply[0]->toString()); + } + + public function testMessageResponseHasToAddress() + { + $_SERVER['SERVER_NAME'] = 'localhost'; + $iTip = $this->_getItip(); + $reply = $iTip->getMessageResponse( + new Horde_Itip_Response_Type_Accept(), '', '' + ); + + $this->assertContains('To: orga@example.org', $reply[0]->toString()); + } + + public function testMessageResponseHasSubjectAddress() + { + $_SERVER['SERVER_NAME'] = 'localhost'; + $iTip = $this->_getItip(); + $reply = $iTip->getMessageResponse(new Horde_Itip_Response_Type_Accept(), ''); + $this->assertContains('Subject: Accepted: Test', $reply[0]->toString()); + } + + public function testMessageResponseAllowsAddingCommentsToTheSubject() + { + $_SERVER['SERVER_NAME'] = 'localhost'; + $iTip = $this->_getItip(); + $reply = $iTip->getMessageResponse( + new Horde_Itip_Response_Type_Accept(), '', 'info' + ); + $this->assertContains('Subject: Accepted [info]: Test', $reply[0]->toString()); + } + + public function testAttendeeHoldsInformationAboutMailAddress() + { + $iTip = $this->_getItip(); + $reply = $iTip->getVeventResponse( + new Horde_Itip_Response_Type_Accept(), '' + ); + $this->assertEquals($reply->getAttribute('ATTENDEE'), 'MAILTO:test@example.org'); + } + + public function testAttendeeHoldsInformationAboutCommonNameAndStatus() + { + $iTip = $this->_getItip(); + $reply = $iTip->getVeventResponse( + new Horde_Itip_Response_Type_Accept(), '' + ); + $parameters = $reply->getAttribute('ATTENDEE', true); + $this->assertEquals( + array_pop($parameters), + array( + 'CN' => 'Mister Test', + 'PARTSTAT' => 'ACCEPTED' + ) + ); + } + + + /** + * Test the basic iTip handling method. + */ + /* public function testBasic() */ + /* { */ + /* $iTip = new Horde_Itip( */ + /* $request, $resource */ + /* ); */ + /* $reply = $itip->setResponseType($responseType) */ + /* ->setSubjectComment('text') */ + /* ->setMessageComment('text') */ + /* ->setUpdate(true) */ + /* ->getMimeMessage(); */ + /* } */ + + private function _getItip($invitation = null) + { + if ($invitation === null) { + $invitation = $this->_getInvitation(); + } + return Horde_Itip::factory( + $invitation, + $this->_getResource() + ); + } + + private function _getInvitation() + { + $vCal = new Horde_Icalendar(); + $inv = Horde_Icalendar::newComponent('VEVENT', $vCal); + $inv->setAttribute('METHOD', 'REQUEST'); + $inv->setAttribute('UID', '1'); + $inv->setAttribute('SUMMARY', 'Test Invitation'); + $inv->setAttribute('DESCRIPTION', 'You are invited'); + $inv->setAttribute('ORGANIZER', 'orga@example.org'); + $inv->setAttribute('DTSTART', array('20080926T110000')); + $inv->setAttribute('DTEND', array('20080926T120000')); + return $inv; + } + + private function _getResource($mail = null, $cn = null) + { + if ($mail === null) { + $mail = 'test@example.org'; + } + if ($cn === null) { + $cn = 'Mister Test'; + } + return new Horde_Itip_Resource_Base($mail, $cn); + } +} diff --git a/framework/Itip/test/Horde/Itip/phpunit.xml b/framework/Itip/test/Horde/Itip/phpunit.xml new file mode 100644 index 000000000..502d3c9b8 --- /dev/null +++ b/framework/Itip/test/Horde/Itip/phpunit.xml @@ -0,0 +1,8 @@ + + + + + ../../../lib + + + -- 2.11.0