Completed testing of sending the iTip response.
authorGunnar Wrobel <p@rdus.de>
Tue, 10 Aug 2010 16:01:18 +0000 (18:01 +0200)
committerGunnar Wrobel <p@rdus.de>
Wed, 25 Aug 2010 17:21:40 +0000 (19:21 +0200)
imp/lib/tests/Imp/Autoload.php
imp/lib/tests/Imp/Stub/Browser.php [new file with mode: 0644]
imp/lib/tests/Imp/Stub/Identity.php [new file with mode: 0644]
imp/lib/tests/Imp/Stub/Injector.php [new file with mode: 0644]
imp/lib/tests/Imp/Stub/Prefs.php [new file with mode: 0644]
imp/lib/tests/Imp/Stub/Registry.php [new file with mode: 0644]
imp/lib/tests/Imp/Unit/Mime/Viewer/ItipTest.php

index 3fccc64..b44c5f1 100644 (file)
@@ -23,6 +23,8 @@ if (!spl_autoload_functions()) {
             . '} else if (substr($filename, 0, 4) == "IMP/") {'
             . '  $filename = substr($filename, 4);'
             . '  $filename = dirname(__FILE__) . "/../../$filename";'
+            . '} else if ($filename == "IMP") {'
+            . '  $filename = dirname(__FILE__) . "/../../$filename";'
             . '}'
             . '$err_mask = E_ALL ^ E_WARNING;'
             . '$oldErrorReporting = error_reporting($err_mask);'
@@ -34,3 +36,10 @@ if (!spl_autoload_functions()) {
 
 /** Catch strict standards */
 error_reporting(E_ALL | E_STRICT);
+
+/** Load stubs */
+require_once 'Stub/Browser.php';
+require_once 'Stub/Identity.php';
+require_once 'Stub/Injector.php';
+require_once 'Stub/Prefs.php';
+require_once 'Stub/Registry.php';
\ No newline at end of file
diff --git a/imp/lib/tests/Imp/Stub/Browser.php b/imp/lib/tests/Imp/Stub/Browser.php
new file mode 100644 (file)
index 0000000..4d2387a
--- /dev/null
@@ -0,0 +1,14 @@
+<?php
+
+class IMP_Stub_Browser
+{
+    public function hasQuirk($quirk)
+    {
+        return false;
+    }
+
+    public function hasFeature($feature)
+    {
+        return false;
+    }
+}
\ No newline at end of file
diff --git a/imp/lib/tests/Imp/Stub/Identity.php b/imp/lib/tests/Imp/Stub/Identity.php
new file mode 100644 (file)
index 0000000..6edd15e
--- /dev/null
@@ -0,0 +1,41 @@
+<?php
+
+class IMP_Stub_Identity
+{
+    private $id;
+
+    public function getMatchingIdentity($mail)
+    {
+        if ($mail == 'test@example.org') {
+            return 'test';
+        }
+    }
+
+    public function setDefault($id)
+    {
+        if ($id != 'test' && $id != 'other') {
+            throw new Exception("Unexpected default $id!");
+        }
+        $this->_id = $id;
+    }
+
+    public function getFromAddress()
+    {
+        return 'test@example.org';
+    }
+
+    public function getValue($value)
+    {
+        switch ($value) {
+        case 'fullname':
+            return 'Mr. Test';
+        case 'replyto_addr':
+            switch ($this->_id) {
+            case 'test':
+                return 'test@example.org';
+            case 'other':
+                return 'reply@example.org';
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/imp/lib/tests/Imp/Stub/Injector.php b/imp/lib/tests/Imp/Stub/Injector.php
new file mode 100644 (file)
index 0000000..09071a2
--- /dev/null
@@ -0,0 +1,19 @@
+<?php
+
+class IMP_Stub_Injector
+{
+    private $_mail;
+
+    public function getInstance($interface)
+    {
+        switch($interface) {
+        case 'IMP_Identity':
+            return new IMP_Stub_Identity();
+        case 'IMP_Mail':
+            if (!isset($this->_mail)) {
+                $this->_mail = new Horde_Mail_Transport_Mock();
+            }
+            return $this->_mail;
+        }
+    }
+}
\ No newline at end of file
diff --git a/imp/lib/tests/Imp/Stub/Prefs.php b/imp/lib/tests/Imp/Stub/Prefs.php
new file mode 100644 (file)
index 0000000..ec50472
--- /dev/null
@@ -0,0 +1,14 @@
+<?php
+
+class IMP_Stub_Prefs
+{
+    public function getValue($pref)
+    {
+        switch($pref) {
+        case 'date_format':
+            return '%x';
+        case 'twentyFour':
+            return true;
+        }
+    }
+}
\ No newline at end of file
diff --git a/imp/lib/tests/Imp/Stub/Registry.php b/imp/lib/tests/Imp/Stub/Registry.php
new file mode 100644 (file)
index 0000000..e9f2e96
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+
+class IMP_Stub_Registry
+{
+    private $_charset = 'UTF-8';
+
+    public function getCharset()
+    {
+        return $this->_charset;
+    }
+
+    public function setCharset($charset)
+    {
+        $this->_charset = $charset;
+    }
+}
\ No newline at end of file
index ccf137b..b137e07 100644 (file)
@@ -35,14 +35,498 @@ require_once dirname(__FILE__) . '/../../../Autoload.php';
 class Imp_Unit_Mime_Viewer_ItipTest
 extends PHPUnit_Framework_TestCase
 {
-    public function testMinimalItipHandlingSteps()
+    public function setUp()
     {
-        $viewer = $this->getViewer();
+        $GLOBALS['registry'] = new IMP_Stub_Registry();
+        $GLOBALS['browser'] = new IMP_Stub_Browser();
+        $GLOBALS['prefs'] = new IMP_Stub_Prefs();
+        $GLOBALS['injector'] = new IMP_Stub_Injector();
+        $GLOBALS['conf']['server']['name'] = 'localhost';
+        $_GET['identity'] = 'test';
+        $_SERVER['REMOTE_ADDR'] = 'localhost';
+        $_SESSION = array('imp' => array('view' => 'imp'));
     }
 
-    private function getViewer()
+    public function testAcceptingAnInvitationResultsInReplySent()
+    {
+        $_GET['itip_action'] = array(0 => 'accept');
+        $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar());
+        $result = $viewer->render('inline');
+        $result = array_pop($result);
+        $this->assertContains('Reply Sent.', $result['data']);
+    }
+
+    /**
+     * @todo This seems strange. How should the user know that an incomplete
+     * event results in no action but just redisplays the invitation?
+     */
+    public function testAcceptingAnInvitationWithoutOrganizerResultsInNoAction()
+    {
+        $_GET['itip_action'] = array(0 => 'accept');
+        $vCal = new Horde_Icalendar();
+        $vCal->setAttribute('METHOD', 'REQUEST');
+        $inv = Horde_Icalendar::newComponent('VEVENT', $vCal);
+        $inv->setAttribute('UID', '1');
+        $viewer = $this->_getViewer($inv->exportvCalendar());
+        $viewer->render('inline');
+        $mail = $this->_getMail();
+        $this->assertEquals('', $mail);
+    }
+
+    public function testAcceptingAnInvitationResultsInMimeMessageSent()
+    {
+        $_GET['itip_action'] = array(0 => 'accept');
+        $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar());
+        $viewer->render('inline');
+        $this->assertType('Horde_Icalendar', $this->_getIcalendar());
+    }
+
+    public function testResultMessageContainsProductId()
+    {
+        $_GET['itip_action'] = array(0 => 'accept');
+        $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar());
+        $viewer->render('inline');
+        $this->assertEquals('-//The Horde Project//Horde Application Framework 4//EN', $this->_getIcalendar()->getAttribute('PRODID'));
+    }
+
+    public function testResultMessageIndicatesMethodReply()
+    {
+        $_GET['itip_action'] = array(0 => 'accept');
+        $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar());
+        $viewer->render('inline');
+        $this->assertEquals('REPLY', $this->_getIcalendar()->getAttribute('METHOD'));
+    }
+
+    public function testResultMessageContainsVevent()
+    {
+        $_GET['itip_action'] = array(0 => 'accept');
+        $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar());
+        $viewer->render('inline');
+        $this->assertType('Horde_Icalendar_Vevent', $this->_getVevent());
+    }
+
+    public function testResultMessageContainsCopiedUid()
+    {
+        $_GET['itip_action'] = array(0 => 'accept');
+        $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar());
+        $viewer->render('inline');
+        $this->assertEquals('1001', $this->_getVevent()->getAttribute('UID'));
+    }
+
+    /**
+     * @todo Should this really throw an exception? Adapt once the Mime Viewer
+     * does error handling (empty array return value)
+     */
+    public function testResultMessageThrowsExceptionIfUidIsMissing()
+    {
+        $_GET['itip_action'] = array(0 => 'accept');
+        $vCal = new Horde_Icalendar();
+        $vCal->setAttribute('METHOD', 'REQUEST');
+        $inv = Horde_Icalendar::newComponent('VEVENT', $vCal);
+        $inv->setAttribute('ORGANIZER', 'somebody@example.com');
+        $viewer = $this->_getViewer($inv->exportvCalendar());
+        $this->assertEquals(array(), $viewer->render('inline'));
+    }
+
+    public function testResultMessageContainsCopiedSummary()
+    {
+        $_GET['itip_action'] = array(0 => 'accept');
+        $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar());
+        $viewer->render('inline');
+        $this->assertEquals('Test Invitation', $this->_getVevent()->getAttribute('SUMMARY'));
+    }
+
+    public function testResultMessageContainsEmptySummaryIfNotAvailable()
+    {
+        $_GET['itip_action'] = array(0 => 'accept');
+        $viewer = $this->_getViewer($this->_getMinimalInvitation()->exportvCalendar());
+        $viewer->render('inline');
+        $this->assertEquals('', $this->_getVevent()->getAttribute('SUMMARY'));
+    }
+
+    public function testResultMessageContainsCopiedDescription()
+    {
+        $_GET['itip_action'] = array(0 => 'accept');
+        $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar());
+        $viewer->render('inline');
+        $this->assertEquals('You are invited', $this->_getVevent()->getAttribute('DESCRIPTION'));
+    }
+
+    public function testResultMessageContainsEmptyDescriptionIfNotAvailable()
+    {
+        $_GET['itip_action'] = array(0 => 'accept');
+        $viewer = $this->_getViewer($this->_getMinimalInvitation()->exportvCalendar());
+        $viewer->render('inline');
+        $this->assertEquals('Default', $this->_getVevent()->getAttributeDefault('DESCRIPTION', 'Default'));
+    }
+
+    public function testResultMessageContainsCopiedStartDate()
+    {
+        $_GET['itip_action'] = array(0 => 'accept');
+        $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar());
+        $viewer->render('inline');
+        $this->assertEquals('1222419600', $this->_getVevent()->getAttribute('DTSTART'));
+    }
+
+    public function testResultMessageContainsCopiedStartDateParameters()
+    {
+        $_GET['itip_action'] = array(0 => 'accept');
+        $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar());
+        $viewer->render('inline');
+        $dtstart = $this->_getVevent()->getAttribute('DTSTART', true);
+        $this->assertEquals(array('TEST' => 'start'), array_pop($dtstart));
+    }
+
+    public function testResultMessageContainsCopiedEndDate()
+    {
+        $_GET['itip_action'] = array(0 => 'accept');
+        $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar());
+        $viewer->render('inline');
+        $this->assertEquals('1222423200', $this->_getVevent()->getAttribute('DTEND'));
+    }
+
+    public function testResultMessageContainsCopiedEndDateParameters()
+    {
+        $_GET['itip_action'] = array(0 => 'accept');
+        $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar());
+        $viewer->render('inline');
+        $dtend = $this->_getVevent()->getAttribute('DTEND', true);
+        $this->assertEquals(array('TEST' => 'end'), array_pop($dtend));
+    }
+
+    public function testResultMessageContainsCopiedDurationIfEndDateIsMissing()
+    {
+        $_GET['itip_action'] = array(0 => 'accept');
+        $start = new Horde_Date('20080926T110000');
+        $vCal = new Horde_Icalendar();
+        $vCal->setAttribute('METHOD', 'REQUEST');
+        $inv = Horde_Icalendar::newComponent('VEVENT', $vCal);
+        $inv->setAttribute('UID', '1001');
+        $inv->setAttribute('ORGANIZER', 'orga@example.org');
+        $inv->setAttribute('DTSTART', $start->timestamp());
+        $inv->setAttribute('DURATION', '3600', array('TEST' => 'duration'));
+        $viewer = $this->_getViewer($inv->exportvCalendar());
+        $viewer->render('inline');
+        $this->assertEquals('3600', $this->_getVevent()->getAttribute('DURATION'));
+    }
+
+    public function testResultMessageContainsCopiedDurationParametersIfEndDateIsMissing()
+    {
+        $_GET['itip_action'] = array(0 => 'accept');
+        $start = new Horde_Date('20080926T110000');
+        $vCal = new Horde_Icalendar();
+        $vCal->setAttribute('METHOD', 'REQUEST');
+        $inv = Horde_Icalendar::newComponent('VEVENT', $vCal);
+        $inv->setAttribute('UID', '1001');
+        $inv->setAttribute('ORGANIZER', 'orga@example.org');
+        $inv->setAttribute('DTSTART', $start->timestamp());
+        $inv->setAttribute('DURATION', '3600', array('TEST' => 'duration'));
+        $viewer = $this->_getViewer($inv->exportvCalendar());
+        $viewer->render('inline');
+        $duration = $this->_getVevent()->getAttribute('DURATION', true);
+        $this->assertEquals(array('TEST' => 'duration'), array_pop($duration));
+    }
+
+    public function testResultMessageContainsCopiedInvitation()
+    {
+        $_GET['itip_action'] = array(0 => 'accept');
+        $inv = $this->_getInvitation();
+        $inv->setAttribute('SEQUENCE', '10');
+        $viewer = $this->_getViewer($inv->exportvCalendar());
+        $viewer->render('inline');
+        $this->assertEquals('10', $this->_getVevent()->getAttribute('SEQUENCE'));
+    }
+
+    public function testResultMessageContainsNoSequenceIfNotAvailable()
+    {
+        $_GET['itip_action'] = array(0 => 'accept');
+        $viewer = $this->_getViewer($this->_getMinimalInvitation()->exportvCalendar());
+        $viewer->render('inline');
+        $this->assertEquals('99', $this->_getVevent()->getAttributeDefault('SEQUENCE', '99'));
+    }
+
+    public function testResultMessageContainsCopiedOrganizer()
+    {
+        $_GET['itip_action'] = array(0 => 'accept');
+        $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar());
+        $viewer->render('inline');
+        $this->assertEquals('mailto:orga@example.org', $this->_getVevent()->getAttribute('ORGANIZER'));
+    }
+
+    public function testResultMessageContainsCopiedOrganizerParameters()
+    {
+        $_GET['itip_action'] = array(0 => 'accept');
+        $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar());
+        $viewer->render('inline');
+        $organizer = $this->_getVevent()->getAttribute('ORGANIZER', true);
+        $this->assertEquals(array('CN' => 'Mr. Orga'), array_pop($organizer));
+    }
+
+    public function testResultMessageContainsAttendeeEmail()
+    {
+        $_GET['itip_action'] = array(0 => 'accept');
+        $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar());
+        $viewer->render('inline');
+        $this->assertEquals('mailto:test@example.org', $this->_getVevent()->getAttribute('ATTENDEE'));
+    }
+
+    public function testResultMessageContainsAttendeeName()
+    {
+        $_GET['itip_action'] = array(0 => 'accept');
+        $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar());
+        $viewer->render('inline');
+        $attendee = $this->_getVevent()->getAttribute('ATTENDEE', true);
+        $params = array_pop($attendee);
+        $this->assertEquals('Mr. Test', $params['CN']);
+    }
+
+    public function testAcceptActionResultsInMessageWithAttendeeStatusAccept()
+    {
+        $_GET['itip_action'] = array(0 => 'accept');
+        $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar());
+        $viewer->render('inline');
+        $attendee = $this->_getVevent()->getAttribute('ATTENDEE', true);
+        $params = array_pop($attendee);
+        $this->assertEquals('ACCEPTED', $params['PARTSTAT']);
+    }
+
+    public function testDenyActionResultsInMessageWithAttendeeStatusDecline()
+    {
+        $_GET['itip_action'] = array(0 => 'deny');
+        $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar());
+        $viewer->render('inline');
+        $attendee = $this->_getVevent()->getAttribute('ATTENDEE', true);
+        $params = array_pop($attendee);
+        $this->assertEquals('DECLINED', $params['PARTSTAT']);
+    }
+
+    public function testTentativeActionResultsInMessageWithAttendeeStatusTentative()
+    {
+        $_GET['itip_action'] = array(0 => 'tentative');
+        $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar());
+        $viewer->render('inline');
+        $attendee = $this->_getVevent()->getAttribute('ATTENDEE', true);
+        $params = array_pop($attendee);
+        $this->assertEquals('TENTATIVE', $params['PARTSTAT']);
+    }
+
+    public function testResultIsAMultipartMimeMessage()
+    {
+        $_GET['itip_action'] = array(0 => 'accept');
+        $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar());
+        $viewer->render('inline');
+        $this->assertEquals('multipart/alternative', $this->_getMimeMessage()->getType());
+    }
+
+    public function testAcceptResultContainsAcceptMimeMessage()
+    {
+        $_GET['itip_action'] = array(0 => 'accept');
+        $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar());
+        $viewer->render('inline');
+        $this->assertEquals('Mr. Test has accepted.', $this->_getMimeMessage()->getPart(1)->getContents());
+    }
+
+    public function testDenyResultContainsDeclineMimeMessage()
+    {
+        $_GET['itip_action'] = array(0 => 'deny');
+        $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar());
+        $viewer->render('inline');
+        $this->assertEquals('Mr. Test has declined.', $this->_getMimeMessage()->getPart(1)->getContents());
+    }
+
+    public function testTentativeResultContainsTentativeMimeMessage()
+    {
+        $_GET['itip_action'] = array(0 => 'tentative');
+        $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar());
+        $viewer->render('inline');
+        $this->assertEquals('Mr. Test has tentatively accepted.', $this->_getMimeMessage()->getPart(1)->getContents());
+    }
+
+    public function testResultMimeMessagePartOneHasRegistryCharset()
+    {
+        $GLOBALS['registry']->setCharset('BIG5');
+        $_GET['itip_action'] = array(0 => 'accept');
+        $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar());
+        $viewer->render('inline');
+        $this->assertEquals('BIG5', $this->_getMimeMessage()->getPart(1)->getCharset());
+    }
+
+    public function testResultMimeMessagePartTwoHasRegistryCharset()
+    {
+        $GLOBALS['registry']->setCharset('BIG5');
+        $_GET['itip_action'] = array(0 => 'accept');
+        $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar());
+        $viewer->render('inline');
+        $this->assertEquals('BIG5', $this->_getMimeMessage()->getPart(2)->getCharset());
+    }
+
+    public function testResultMimeMessagePartTwoHasFileName()
+    {
+        $_GET['itip_action'] = array(0 => 'accept');
+        $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar());
+        $viewer->render('inline');
+        $this->assertEquals('event-reply.ics', $this->_getMimeMessage()->getPart(2)->getName());
+    }
+
+    public function testResultMimeMessagePartTwoHasContentTypeParameter()
+    {
+        $_GET['itip_action'] = array(0 => 'accept');
+        $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar());
+        $viewer->render('inline');
+        $this->assertEquals('REPLY', $this->_getMimeMessage()->getPart(2)->getContentTypeParameter('METHOD'));
+    }
+
+    public function testResultMimeMessageHeadersContainsReceivedHeader()
+    {
+        $_GET['itip_action'] = array(0 => 'accept');
+        $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar());
+        $viewer->render('inline');
+        $this->assertContains('(Horde Framework) with HTTP', $this->_getMailHeaders()->getValue('Received'));
+    }
+
+    public function testResultMimeMessageHeadersContainsMessageId()
+    {
+        $_GET['itip_action'] = array(0 => 'accept');
+        $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar());
+        $viewer->render('inline');
+        $this->assertContains('.Horde.', $this->_getMailHeaders()->getValue('Message-ID'));
+    }
+
+    public function testResultMimeMessageHeadersContainsDate()
+    {
+        $_GET['itip_action'] = array(0 => 'accept');
+        $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar());
+        $viewer->render('inline');
+        $date = $this->_getMailHeaders()->getValue('Date');
+        $this->assertTrue(!empty($date));
+    }
+
+    public function testResultMimeMessageHeadersContainsFrom()
+    {
+        $_GET['itip_action'] = array(0 => 'accept');
+        $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar());
+        $viewer->render('inline');
+        $this->assertEquals('test@example.org', $this->_getMailHeaders()->getValue('From'));
+    }
+
+    public function testResultMimeMessageHeadersContainsTo()
+    {
+        $_GET['itip_action'] = array(0 => 'accept');
+        $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar());
+        $viewer->render('inline');
+        $this->assertEquals('orga@example.org', $this->_getMailHeaders()->getValue('To'));
+    }
+
+    public function testAcceptActionResultMimeMessageHeadersContainsAcceptSubject()
+    {
+        $_GET['itip_action'] = array(0 => 'accept');
+        $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar());
+        $viewer->render('inline');
+        $this->assertEquals('Accepted: Test Invitation', $this->_getMailHeaders()->getValue('Subject'));
+    }
+
+    public function testDenyActionResultMimeMessageHeadersContainsDeclineSubject()
+    {
+        $_GET['itip_action'] = array(0 => 'deny');
+        $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar());
+        $viewer->render('inline');
+        $this->assertEquals('Declined: Test Invitation', $this->_getMailHeaders()->getValue('Subject'));
+    }
+
+    public function testTentativeActionResultMimeMessageHeadersContainsTentativeSubject()
+    {
+        $_GET['itip_action'] = array(0 => 'tentative');
+        $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar());
+        $viewer->render('inline');
+        $this->assertEquals('Tentative: Test Invitation', $this->_getMailHeaders()->getValue('Subject'));
+    }
+    public function testResultMimeMessageHeadersContainsReplyToForAlternateIdentity()
+    {
+        $_GET['identity'] = 'other';
+        $_GET['itip_action'] = array(0 => 'accept');
+        $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar());
+        $viewer->render('inline');
+        $this->assertEquals('reply@example.org', $this->_getMailHeaders()->getValue('Reply-To'));
+    }
+
+    private function _getViewer($invitation)
     {
         $part = new Horde_Mime_Part();
+        $part->setContents($invitation);
         return new IMP_Horde_Mime_Viewer_Itip($part);
     }
+
+    private function _getInvitation()
+    {
+        $start = new Horde_Date('20080926T110000');
+        $end = new Horde_Date('20080926T120000');
+        $vCal = new Horde_Icalendar();
+        $vCal->setAttribute('METHOD', 'REQUEST');
+        $inv = Horde_Icalendar::newComponent('VEVENT', $vCal);
+        $inv->setAttribute('UID', '1001');
+        $inv->setAttribute('SUMMARY', 'Test Invitation');
+        $inv->setAttribute('DESCRIPTION', 'You are invited');
+        $inv->setAttribute('LOCATION', 'Somewhere');
+        $inv->setAttribute('ORGANIZER', 'mailto:orga@example.org', array('cn' => 'Mr. Orga'));
+        $inv->setAttribute('DTSTART', $start->timestamp(), array('TEST' => 'start'));
+        $inv->setAttribute('DTEND', $end->timestamp(), array('TEST' => 'end'));
+        $inv->setAttribute('ATTENDEE', 'mailto:orga@example.org', array('CN' => 'Mr. Orga'));
+        $inv->setAttribute('ATTENDEE', 'mailto:test@example.org', array('CN' => 'Mr. Test'));
+        return $inv;
+    }
+
+    private function _getMinimalInvitation()
+    {
+        $start = new Horde_Date('20080926T110000');
+        $end = new Horde_Date('20080926T120000');
+        $vCal = new Horde_Icalendar();
+        $vCal->setAttribute('METHOD', 'REQUEST');
+        $inv = Horde_Icalendar::newComponent('VEVENT', $vCal);
+        $inv->setAttribute('UID', '1001');
+        $inv->setAttribute('ORGANIZER', 'mailto:orga@example.org', array('cn' => 'Mr. Orga'));
+        $inv->setAttribute('DTSTART', $start->timestamp());
+        $inv->setAttribute('DTEND', $end->timestamp());
+        return $inv;
+    }
+
+    private function _getMailHeaders()
+    {
+        if (isset($GLOBALS['injector']->getInstance('IMP_Mail')->sentMessages[0])) {
+            return Horde_Mime_Headers::parseHeaders(
+                $GLOBALS['injector']->getInstance('IMP_Mail')->sentMessages[0]['header_text']
+            );
+        }
+    }
+
+    private function _getMail()
+    {
+        $mail = '';
+        if (isset($GLOBALS['injector']->getInstance('IMP_Mail')->sentMessages[0])) {
+            $mail .= $GLOBALS['injector']->getInstance('IMP_Mail')->sentMessages[0]['header_text'] . "\n\n";
+            $body = $GLOBALS['injector']->getInstance('IMP_Mail')->sentMessages[0]['body'];
+            while (!feof($body)) {
+                $mail .= fread($body, 8192);
+            }
+        }
+        return $mail;
+    }
+
+    private function _getMimeMessage()
+    {
+        $mail = $this->_getMail();
+        return Horde_Mime_Part::parseMessage($mail);
+    }
+
+    private function _getIcalendar()
+    {
+        $part = $this->_getMimeMessage();
+        $iCal = new Horde_Icalendar();
+        $iCal->parsevCalendar($part->getPart(2)->getContents());
+        return $iCal;
+    }
+
+    private function _getVevent()
+    {
+        return $this->_getIcalendar()->getComponent(0);
+    }
 }