[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [kdepimlibs/KDE/4.11] akonadi/calendar/tests: sync the unit-tests with master.
From:       Sergio Martins <iamsergio () gmail ! com>
Date:       2013-10-31 21:45:18
Message-ID: E1Vc03K-00014u-5A () scm ! kde ! org
[Download RAW message or body]

Git commit d662dbc0c4947b3cffacc4410f5852710a6df481 by Sergio Martins.
Committed on 31/10/2013 at 21:41.
Pushed by smartins into branch 'KDE/4.11'.

sync the unit-tests with master.

This makes much easier to be able to commit in KDE/4.11 and merge
to master. Otherwise I'd have to commit a fix in KDE/4.11 and then
commit the unit test in master, since akonadi isolated tests
don't run on KDE/4.11

A  +41   -0    akonadi/calendar/tests/helper.cpp     [License: UNKNOWN]  *
A  +32   -0    akonadi/calendar/tests/helper.h     [License: LGPL (v2+)]
M  +6    -53   akonadi/calendar/tests/historytest.cpp
M  +2    -6    akonadi/calendar/tests/historytest.h
M  +7    -1    akonadi/calendar/tests/incidencechangertest.cpp
A  +47   -0    akonadi/calendar/tests/itip_data/bug235749
A  +41   -0    akonadi/calendar/tests/itip_data/expected_data/cancel1
A  +22   -0    akonadi/calendar/tests/itip_data/expected_data/update1
A  +23   -0    akonadi/calendar/tests/itip_data/expected_data/update2
A  +42   -0    akonadi/calendar/tests/itip_data/expected_data/update3
A  +23   -0    akonadi/calendar/tests/itip_data/invited_us
A  +24   -0    akonadi/calendar/tests/itip_data/invited_us_cancel01
A  +27   -0    akonadi/calendar/tests/itip_data/invited_us_daily
A  +43   -0    akonadi/calendar/tests/itip_data/invited_us_daily_cancel01
A  +22   -0    akonadi/calendar/tests/itip_data/invited_us_daily_cancel_recid01
A  +25   -0    akonadi/calendar/tests/itip_data/invited_us_daily_update01
A  +26   -0    akonadi/calendar/tests/itip_data/invited_us_daily_update_recid01
A  +23   -0    akonadi/calendar/tests/itip_data/invited_us_update01
A  +616  -0    akonadi/calendar/tests/itiphandlertest.cpp     [License: LGPL (v2+)]
A  +92   -0    akonadi/calendar/tests/itiphandlertest.h     [License: LGPL (v2+)]
M  +50   -37   akonadi/calendar/tests/mailclienttest.cpp
A  +207  -0    akonadi/calendar/tests/todopurgertest.cpp     [License: LGPL (v2+)]
A  +65   -0    akonadi/calendar/tests/todopurgertest.h     [License: LGPL (v2+)]
A  +198  -0    akonadi/calendar/tests/unittestbase.cpp     [License: LGPL (v2+)]
A  +60   -0    akonadi/calendar/tests/unittestbase.h     [License: LGPL (v2+)]
M  +0    -2    akonadi/calendar/tests/unittestenv/config-sqlite-db.xml
D  +0    -2    akonadi/calendar/tests/unittestenv/kdehome/share/config/akonadi_maildir_resource_0rc
 D  +0    -2    akonadi/calendar/tests/unittestenv/kdehome/share/config/akonadi_mailtransport_dummy_resource_0rc
 A  +1672 -0    akonadi/calendar/tests/unittestenv/kdehome/share/config/kdebugrc

The files marked with a * at the end have a non valid license. Please read: \
http://techbase.kde.org/Policies/Licensing_Policy and use the headers which are \
listed at that page.


http://commits.kde.org/kdepimlibs/d662dbc0c4947b3cffacc4410f5852710a6df481

diff --git a/akonadi/calendar/tests/helper.cpp b/akonadi/calendar/tests/helper.cpp
new file mode 100644
index 0000000..a152345
--- /dev/null
+++ b/akonadi/calendar/tests/helper.cpp
@@ -0,0 +1,41 @@
+#include "helper.h"
+
+#include <akonadi/itemfetchjob.h>
+#include <akonadi/collectionfetchjob.h>
+#include <akonadi/collectionfetchscope.h>
+
+#include <QLatin1String>
+#include <QStringList>
+
+using namespace Akonadi;
+
+bool Helper::confirmExists(const Akonadi::Item &item)
+{
+    ItemFetchJob *job = new ItemFetchJob(item);
+    return job->exec() != 0;
+}
+
+bool Helper::confirmDoesntExist(const Akonadi::Item &item)
+{
+    ItemFetchJob *job = new ItemFetchJob(item);
+    return job->exec() == 0;
+}
+
+
+Akonadi::Collection Helper::fetchCollection()
+{
+    CollectionFetchJob *job = new CollectionFetchJob(Collection::root(),
+                                                     CollectionFetchJob::Recursive);
+    // Get list of collections
+    job->fetchScope().setContentMimeTypes(QStringList() << \
QLatin1String("application/x-vnd.akonadi.calendar.event")); +    const bool ret = \
job->exec(); +    Q_ASSERT(ret);
+
+    // Find our collection
+    Collection::List collections = job->collections();
+    Collection collection = collections.first();
+
+    Q_ASSERT(collection.isValid());
+
+    return collection;
+}
diff --git a/akonadi/calendar/tests/helper.h b/akonadi/calendar/tests/helper.h
new file mode 100644
index 0000000..2aee89b
--- /dev/null
+++ b/akonadi/calendar/tests/helper.h
@@ -0,0 +1,32 @@
+/*
+    Copyright (c) 2013 Sérgio Martins <iamsergio@gmail.com>
+
+    This library is free software; you can redistribute it and/or modify it
+    under the terms of the GNU Library General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    This library is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
+    License for more details.
+
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to the
+    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301, USA.
+*/
+
+#ifndef HELPER_H_
+#define HELPER_H_
+
+#include <akonadi/collection.h>
+#include <akonadi/item.h>
+
+namespace Helper {
+    bool confirmExists(const Akonadi::Item &item);
+    bool confirmDoesntExist(const Akonadi::Item &item);
+    Akonadi::Collection fetchCollection();
+}
+
+#endif
diff --git a/akonadi/calendar/tests/historytest.cpp \
b/akonadi/calendar/tests/historytest.cpp index b2b8bd3..2344c30 100644
--- a/akonadi/calendar/tests/historytest.cpp
+++ b/akonadi/calendar/tests/historytest.cpp
@@ -18,6 +18,7 @@
 */
 
 #include "historytest.h"
+#include "helper.h"
 
 #include <akonadi/itemfetchjob.h>
 #include <akonadi/itemcreatejob.h>
@@ -25,7 +26,6 @@
 #include <akonadi/collectionfetchscope.h>
 #include <akonadi/itemfetchscope.h>
 #include <akonadi/qtest_akonadi.h>
-
 #include <kcalcore/event.h>
 
 #include <QTestEventLoop>
@@ -35,17 +35,6 @@ using namespace KCalCore;
 
 Q_DECLARE_METATYPE(QList<Akonadi::IncidenceChanger::ChangeType>)
 
-static bool confirmExists(const Akonadi::Item &item)
-{
-    ItemFetchJob *job = new ItemFetchJob(item);
-    return job->exec() != 0;
-}
-
-static bool confirmDoesntExists(const Akonadi::Item &item)
-{
-    ItemFetchJob *job = new ItemFetchJob(item);
-    return job->exec() == 0;
-}
 
 static bool checkSummary(const Akonadi::Item &item, const QString &expected)
 {
@@ -85,48 +74,12 @@ static Akonadi::Item createItem(const Akonadi::Collection \
&collection)  return createJob->item();
 }
 
-void HistoryTest::createIncidence(const QString &uid)
-{
-    Item item;
-    item.setMimeType(Event::eventMimeType());
-    Incidence::Ptr incidence = Incidence::Ptr(new Event());
-    incidence->setUid(uid);
-    incidence->setSummary(QLatin1String("summary"));
-    item.setPayload<KCalCore::Incidence::Ptr>(incidence);
-    ItemCreateJob *job = new ItemCreateJob(item, mCollection, this);
-    AKVERIFYEXEC(job);
-}
-
-void HistoryTest::fetchCollection()
-{
-    CollectionFetchJob *job = new CollectionFetchJob(Collection::root(),
-                                                     CollectionFetchJob::Recursive,
-                                                     this);
-    // Get list of collections
-    job->fetchScope().setContentMimeTypes(QStringList() << \
                QLatin1String("application/x-vnd.akonadi.calendar.event"));
-    AKVERIFYEXEC(job);
-
-    // Find our collection
-    Collection::List collections = job->collections();
-    QVERIFY(!collections.isEmpty());
-    mCollection = collections.first();
-
-    QVERIFY(mCollection.isValid());
-}
-
 void HistoryTest::initTestCase()
 {
     AkonadiTest::checkTestIsIsolated();
 
-    fetchCollection();
-    qRegisterMetaType<Akonadi::Item>("Akonadi::Item");
-    qRegisterMetaType<QList<Akonadi::IncidenceChanger::ChangeType> \
                >("QList<Akonadi::IncidenceChanger::ChangeType>");
-    qRegisterMetaType<QVector<Akonadi::Item::Id> >("QVector<Akonadi::Item::Id>");
-    mChanger = new IncidenceChanger(this);
-    mChanger->setShowDialogsOnError(false);
-    mChanger->setHistoryEnabled(true);
     mHistory = mChanger->history();
-    mChanger->setDefaultCollection(mCollection);
+
     connect(mChanger,
              SIGNAL(createFinished(int,Akonadi::Item,Akonadi::IncidenceChanger::ResultCode,QString)),
                
              SLOT(createFinished(int,Akonadi::Item,Akonadi::IncidenceChanger::ResultCode,QString)));
 @@ -165,7 +118,7 @@ void HistoryTest::testCreation()
     waitForSignals();
 
     // Check that it was created
-    QVERIFY(confirmExists(mItemByChangeId.value(changeId)));
+    QVERIFY(Helper::confirmExists(mItemByChangeId.value(changeId)));
 
     QCOMPARE(mHistory->d->redoCount(), 0);
     QCOMPARE(mHistory->d->undoCount(), 1);
@@ -176,7 +129,7 @@ void HistoryTest::testCreation()
     waitForSignals();
 
     // Check that it doesn't exist anymore
-    QVERIFY(confirmDoesntExists(mItemByChangeId.value(changeId)));
+    QVERIFY(Helper::confirmDoesntExist(mItemByChangeId.value(changeId)));
 
     QCOMPARE(mHistory->d->redoCount(), 1);
     QCOMPARE(mHistory->d->undoCount(), 0);
@@ -227,7 +180,7 @@ void HistoryTest::testDeletion()
 
     // Check that it doesn't exist anymore
     foreach(const Akonadi::Item &item, items) {
-        QVERIFY(confirmDoesntExists(item));
+        QVERIFY(Helper::confirmDoesntExist(item));
     }
 
     mPendingSignals[UndoSignal] = 1;
@@ -397,7 +350,7 @@ void HistoryTest::testAtomicOperations()
             // It changed id, have no way to verify
             break;
         case IncidenceChanger::ChangeTypeDelete:
-            QVERIFY(confirmDoesntExists(item));
+            QVERIFY(Helper::confirmDoesntExist(item));
             break;
         case IncidenceChanger::ChangeTypeModify:
             QVERIFY(checkSummary(item, QLatin1String("random summary")));
diff --git a/akonadi/calendar/tests/historytest.h \
b/akonadi/calendar/tests/historytest.h index f66d2ad..c274acf 100644
--- a/akonadi/calendar/tests/historytest.h
+++ b/akonadi/calendar/tests/historytest.h
@@ -20,6 +20,7 @@
 #ifndef HISTORY_TEST_H
 #define HISTORY_TEST_H
 
+#include "unittestbase.h"
 #include "../history.h"
 #include "../history_p.h"
 #include "../incidencechanger.h"
@@ -33,19 +34,14 @@ enum SignalType {
     NumSignals
 };
 
-class HistoryTest : public QObject
+class HistoryTest : public UnitTestBase
 {
     Q_OBJECT
-    Collection mCollection;
-    IncidenceChanger *mChanger;
     History *mHistory;
     QHash<SignalType, int> mPendingSignals;
     QHash<int, Akonadi::Item> mItemByChangeId;
     QList<int> mKnownChangeIds;
 
-    void createIncidence(const QString &uid);
-    void fetchCollection();
-
 private Q_SLOTS:
     void initTestCase();
 
diff --git a/akonadi/calendar/tests/incidencechangertest.cpp \
b/akonadi/calendar/tests/incidencechangertest.cpp index b9136a9..aa844f2 100644
--- a/akonadi/calendar/tests/incidencechangertest.cpp
+++ b/akonadi/calendar/tests/incidencechangertest.cpp
@@ -165,6 +165,12 @@ class IncidenceChangerTest : public QObject
                                             << \
                IncidenceChanger::DestinationPolicyDefault
                                             << false << \
IncidenceChanger::ResultCodeSuccess;  
+      // In this case, the collection dialog shouldn't be shown, as we only have 1 \
collection +      QTest::newRow( "Only one collection" ) << false << "SomeUid6" << \
"Summary6" << Collection() +                                             << \
Collection() << true +                                             << \
IncidenceChanger::DestinationPolicyAsk +                                             \
<< false << IncidenceChanger::ResultCodeSuccess; +
       Collection collectionWithoutRights = Collection( mCollection.id() );
       collectionWithoutRights.setRights( Collection::Rights() );
       Q_ASSERT( ( mCollection.rights() & Akonadi::Collection::CanCreateItem ) );
@@ -250,7 +256,7 @@ class IncidenceChangerTest : public QObject
       Item::List items = fetchJob->items();
 
       // 5 Incidences were created in testCreating(). Keep this in sync.
-      QVERIFY( items.count() == 4 );
+      QCOMPARE( items.count(), 5 );
       QTest::newRow( "Simple delete" ) << (Item::List() << items.at( 0 ) ) << true \
                << false
                                        << IncidenceChanger::ResultCodeSuccess;
 
diff --git a/akonadi/calendar/tests/itip_data/bug235749 \
b/akonadi/calendar/tests/itip_data/bug235749 new file mode 100644
index 0000000..6854c94
--- /dev/null
+++ b/akonadi/calendar/tests/itip_data/bug235749
@@ -0,0 +1,47 @@
+BEGIN:VCALENDAR
+PRODID:-//Unittest
+VERSION:2.0
+CALSCALE:GREGORIAN
+METHOD:REQUEST
+
+BEGIN:VTIMEZONE
+TZID:America/Toronto
+X-LIC-LOCATION:America/Toronto
+BEGIN:DAYLIGHT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+TZNAME:EDT
+DTSTART:19700308T020000
+RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=2SU;BYMONTH=3
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+TZNAME:EST
+DTSTART:19701101T020000
+RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=1SU;BYMONTH=11
+END:STANDARD
+END:VTIMEZONE
+
+BEGIN:VEVENT
+DTSTART:20100430T140000Z
+DTEND:20100430T150000Z
+ORGANIZER;RSVP=TRUE;PARTSTAT=ACCEPTED;ROLE=CHAIR:mailto:xyz@yahoo.ca
+UID:b6f0466a-8877-49d0-a4fc-8ee18ffd8e07
+ATTENDEE;RSVP=TRUE;CN=XYZ;PARTSTAT=NEEDS-ACTION;
+ ROLE=REQ-PARTICIPANT:mailto:mailto:unittests@dev.nul
+ATTENDEE;RSVP=TRUE;CN=XYZ;PARTSTAT=NEEDS-ACTION;
+ ROLE=REQ-PARTICIPANT:mailto:xyz@pqr.com
+ATTENDEE;RSVP=TRUE;CN='XYZ';PARTSTAT=NEEDS-ACTION;
+ ROLE=REQ-PARTICIPANT:mailto:xyz@pqr.com
+CREATED:20100429T181532Z
+LAST-MODIFIED:20100429T182209Z
+DTSTAMP:20100429T182209Z
+SEQUENCE:0
+STATUS:CONFIRMED
+SUMMARY:sync up on deployment practices
+LOCATION:BoardroomA
+DESCRIPTION:- sync up on current deployment practices\n- discuss futuredeployment \
steps\, production environment +TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
diff --git a/akonadi/calendar/tests/itip_data/expected_data/cancel1 \
b/akonadi/calendar/tests/itip_data/expected_data/cancel1 new file mode 100644
index 0000000..d91d016
--- /dev/null
+++ b/akonadi/calendar/tests/itip_data/expected_data/cancel1
@@ -0,0 +1,41 @@
+BEGIN:VCALENDAR
+PRODID:-//K Desktop Environment//NONSGML libkcal 4.3//EN
+VERSION:2.0
+BEGIN:VEVENT
+ORGANIZER:MAILTO:their-email@dev.nul
+DTSTAMP:20131025T103442Z
+ATTENDEE;RSVP=TRUE;PARTSTAT=ACCEPTED;ROLE=REQ-PARTICIPANT;
+ X-UID=their-email@dev.nul:mailto:their-email@dev.nul
+ATTENDEE;CN="unittests@dev.nul";RSVP=TRUE;PARTSTAT=ACCEPTED;
+ ROLE=REQ-PARTICIPANT;X-UID=unittests@dev.nul:mailto:unittests@dev.nul
+CREATED:20131022T230432Z
+UID:uosj936i6arrtl9c2i5r2mfuvg
+LAST-MODIFIED:20131025T103442Z
+DESCRIPTION:Foo
+SUMMARY:Daily stuff
+STATUS:CONFIRMED
+RRULE:FREQ=DAILY
+DTSTART:20131022T090000Z
+DTEND:20131022T100000Z
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+ORGANIZER:MAILTO:their-email@dev.nul
+DTSTAMP:20131025T103442Z
+ATTENDEE;RSVP=TRUE;PARTSTAT=ACCEPTED;ROLE=REQ-PARTICIPANT;
+ X-UID=their-email@dev.nul:mailto:their-email@dev.nul
+ATTENDEE;RSVP=TRUE;PARTSTAT=ACCEPTED;ROLE=REQ-PARTICIPANT;
+ X-UID=unittests@dev.nul:mailto:unittests@dev.nul
+CREATED:20131023T175039Z
+UID:uosj936i6arrtl9c2i5r2mfuvg
+SEQUENCE:1
+LAST-MODIFIED:20131025T103442Z
+DESCRIPTION:Foo
+SUMMARY:Daily stuff
+STATUS:CANCELLED
+RECURRENCE-ID:20131024T000000Z
+DTSTART:20131024T000000Z
+DTEND:20131024T010000Z
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
diff --git a/akonadi/calendar/tests/itip_data/expected_data/update1 \
b/akonadi/calendar/tests/itip_data/expected_data/update1 new file mode 100644
index 0000000..c767ecb
--- /dev/null
+++ b/akonadi/calendar/tests/itip_data/expected_data/update1
@@ -0,0 +1,22 @@
+BEGIN:VCALENDAR
+PRODID:-//K Desktop Environment//NONSGML libkcal 4.3//EN
+VERSION:2.0
+BEGIN:VEVENT
+ORGANIZER;CN="iamsergio@gmail.com":MAILTO:iamsergio@gmail.com
+DTSTAMP:20131025T103442Z
+ATTENDEE;RSVP=TRUE;PARTSTAT=ACCEPTED;ROLE=REQ-PARTICIPANT;
+ X-UID=140218346340032:mailto:their-email@dev.nul
+ATTENDEE;CN="sergio.martins@kdab.com";RSVP=TRUE;PARTSTAT=ACCEPTED;
+ ROLE=REQ-PARTICIPANT;X-UID=140218346000928:mailto:unittests@dev.nul
+CREATED:20131019T224011Z
+UID:uosj936i6arrtl9c2i5r2mfuvg
+SEQUENCE:2
+LAST-MODIFIED:20131025T103442Z
+DESCRIPTION:Random desc
+SUMMARY:new-summary
+STATUS:CONFIRMED
+DTSTART:20131022T102000Z
+DTEND:20131022T112000Z
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
diff --git a/akonadi/calendar/tests/itip_data/expected_data/update2 \
b/akonadi/calendar/tests/itip_data/expected_data/update2 new file mode 100644
index 0000000..6c929a3
--- /dev/null
+++ b/akonadi/calendar/tests/itip_data/expected_data/update2
@@ -0,0 +1,23 @@
+BEGIN:VCALENDAR
+PRODID:-//K Desktop Environment//NONSGML libkcal 4.3//EN
+VERSION:2.0
+BEGIN:VEVENT
+ORGANIZER:MAILTO:their-email@dev.nul
+DTSTAMP:20131025T103442Z
+ATTENDEE;RSVP=TRUE;PARTSTAT=ACCEPTED;ROLE=REQ-PARTICIPANT;
+ X-UID=140218346311392:mailto:their-email@dev.nul
+ATTENDEE;CN="unittests@dev.nul";RSVP=TRUE;PARTSTAT=ACCEPTED;
+ ROLE=REQ-PARTICIPANT;X-UID=140218344168032:mailto:unittests@dev.nul
+CREATED:20131023T175039Z
+UID:uosj936i6arrtl9c2i5r2mfuvg
+SEQUENCE:2
+LAST-MODIFIED:20131025T103442Z
+DESCRIPTION:Foo
+SUMMARY:new-summary
+STATUS:CONFIRMED
+RRULE:FREQ=DAILY
+DTSTART:20131022T090000Z
+DTEND:20131022T100000Z
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
diff --git a/akonadi/calendar/tests/itip_data/expected_data/update3 \
b/akonadi/calendar/tests/itip_data/expected_data/update3 new file mode 100644
index 0000000..1e77f88
--- /dev/null
+++ b/akonadi/calendar/tests/itip_data/expected_data/update3
@@ -0,0 +1,42 @@
+BEGIN:VCALENDAR
+PRODID:-//K Desktop Environment//NONSGML libkcal 4.3//EN
+VERSION:2.0
+BEGIN:VEVENT
+ORGANIZER:MAILTO:their-email@dev.nul
+DTSTAMP:20131025T103442Z
+ATTENDEE;RSVP=TRUE;PARTSTAT=ACCEPTED;ROLE=REQ-PARTICIPANT;
+ X-UID=140218344167648:mailto:their-email@dev.nul
+ATTENDEE;CN="unittests@dev.nul";RSVP=TRUE;PARTSTAT=ACCEPTED;
+ ROLE=REQ-PARTICIPANT;X-UID=140218344958464:mailto:unittests@dev.nul
+CREATED:20131022T230432Z
+UID:uosj936i6arrtl9c2i5r2mfuvg
+LAST-MODIFIED:20131025T103442Z
+DESCRIPTION:Foo
+SUMMARY:Daily stuff
+STATUS:CONFIRMED
+RRULE:FREQ=DAILY
+DTSTART:20131022T090000Z
+DTEND:20131022T100000Z
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+ORGANIZER:MAILTO:their-email@dev.nul
+DTSTAMP:20131025T103442Z
+ATTENDEE;RSVP=TRUE;PARTSTAT=ACCEPTED;ROLE=REQ-PARTICIPANT;
+ X-UID=140218346119456:mailto:their-email@dev.nul
+ATTENDEE;CN="unittests@dev.nul";RSVP=TRUE;PARTSTAT=ACCEPTED;
+ ROLE=REQ-PARTICIPANT;X-UID=140218346001408:mailto:unittests@dev.nul
+CREATED:20131023T175039Z
+UID:uosj936i6arrtl9c2i5r2mfuvg
+SEQUENCE:1
+LAST-MODIFIED:20131025T103442Z
+DESCRIPTION:Foo
+SUMMARY:new-summary-for-second-occurrence
+STATUS:CONFIRMED
+RECURRENCE-ID:20131023T090000Z
+RRULE:FREQ=DAILY
+DTSTART:20131023T090000Z
+DTEND:20131023T100000Z
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
diff --git a/akonadi/calendar/tests/itip_data/invited_us \
b/akonadi/calendar/tests/itip_data/invited_us new file mode 100644
index 0000000..cfc0740
--- /dev/null
+++ b/akonadi/calendar/tests/itip_data/invited_us
@@ -0,0 +1,23 @@
+BEGIN:VCALENDAR
+PRODID:-//Unittest
+VERSION:2.0
+CALSCALE:GREGORIAN
+METHOD:REQUEST
+BEGIN:VEVENT
+DTSTART:20131010T110000Z
+DTEND:20131010T140000Z
+DTSTAMP:20131010T210701Z
+ORGANIZER;CN=their-email@dev.nul:mailto:their-email@dev.nul
+UID:uosj936i6arrtl9c2i5r2mfuvg
+ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;RSVP=TRUE;X-NUM-GUESTS=0:mailto:their-email@dev.nul
 +ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN=sergio.martins@kdab.com;X-NUM-GUESTS=0:mailto:unittests@dev.nul
 +CREATED:20131010T210701Z
+DESCRIPTION:Random desc
+LAST-MODIFIED:20131010T210701Z
+LOCATION:
+SEQUENCE:0
+STATUS:CONFIRMED
+SUMMARY:asd
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
\ No newline at end of file
diff --git a/akonadi/calendar/tests/itip_data/invited_us_cancel01 \
b/akonadi/calendar/tests/itip_data/invited_us_cancel01 new file mode 100644
index 0000000..e8f0c87
--- /dev/null
+++ b/akonadi/calendar/tests/itip_data/invited_us_cancel01
@@ -0,0 +1,24 @@
+BEGIN:VCALENDAR
+PRODID:-//Unittest
+VERSION:2.0
+CALSCALE:GREGORIAN
+METHOD:CANCEL
+BEGIN:VEVENT
+DTSTART:20131010T110000Z
+DTEND:20131010T140000Z
+DTSTAMP:20131022T221237Z
+ORGANIZER;CN=their-email@dev.nul:mailto:their-email@dev.nul
+UID:uosj936i6arrtl9c2i5r2mfuvg
+ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;X-NUM-GUE
+ STS=0:mailto:their-email@dev.nul
+ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;CN=unittests@dev.nul;X-NUM-GUESTS=0:mailto:unittests@dev.nul
 +CREATED:20131022T221005Z
+DESCRIPTION:
+LAST-MODIFIED:20131022T221237Z
+LOCATION:
+SEQUENCE:1
+STATUS:CANCELLED
+SUMMARY:asd
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
diff --git a/akonadi/calendar/tests/itip_data/invited_us_daily \
b/akonadi/calendar/tests/itip_data/invited_us_daily new file mode 100644
index 0000000..d6dccd5
--- /dev/null
+++ b/akonadi/calendar/tests/itip_data/invited_us_daily
@@ -0,0 +1,27 @@
+BEGIN:VCALENDAR
+PRODID:-//
+VERSION:2.0
+CALSCALE:GREGORIAN
+METHOD:REQUEST
+
+BEGIN:VEVENT
+DTSTART:20131022T090000Z
+DTEND:20131022T100000Z
+RRULE:FREQ=DAILY
+DTSTAMP:20131022T230432Z
+ORGANIZER:mailto:their-email@dev.nul
+UID:uosj936i6arrtl9c2i5r2mfuvg
+ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;RSVP=TRUE
+ ;X-NUM-GUESTS=0:mailto:their-email@dev.nul
+ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=
+ TRUE;CN=unittests@dev.nul;X-NUM-GUESTS=0:mailto:unittests@dev.nul
+CREATED:20131022T230432Z
+DESCRIPTION:Foo
+LAST-MODIFIED:20131022T230432Z
+LOCATION:
+SEQUENCE:0
+STATUS:CONFIRMED
+SUMMARY:Daily stuff
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
diff --git a/akonadi/calendar/tests/itip_data/invited_us_daily_cancel01 \
b/akonadi/calendar/tests/itip_data/invited_us_daily_cancel01 new file mode 100644
index 0000000..5d0c347
--- /dev/null
+++ b/akonadi/calendar/tests/itip_data/invited_us_daily_cancel01
@@ -0,0 +1,43 @@
+BEGIN:VCALENDAR
+PRODID:-//
+VERSION:2.0
+CALSCALE:GREGORIAN
+METHOD:CANCEL
+BEGIN:VTIMEZONE
+TZID:Europe/London
+X-LIC-LOCATION:Europe/London
+BEGIN:DAYLIGHT
+TZOFFSETFROM:+0000
+TZOFFSETTO:+0100
+TZNAME:BST
+DTSTART:19700329T010000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:+0100
+TZOFFSETTO:+0000
+TZNAME:GMT
+DTSTART:19701025T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+DTSTART;TZID=Europe/London:20131022T090000
+DTEND;TZID=Europe/London:20131022T100000
+RRULE:FREQ=DAILY
+DTSTAMP:20131022T232159Z
+ORGANIZER:mailto:their-email@dev.nul
+UID:uosj936i6arrtl9c2i5r2mfuvg
+ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;X-NUM-GUE
+ STS=0:mailto:their-email@dev.nul
+ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;CN=unittests@dev.nul;X-NUM-GUESTS=0:mailto:unittests@dev.nul
 +CREATED:20131022T230432Z
+DESCRIPTION:
+LAST-MODIFIED:20131022T232159Z
+LOCATION:
+SEQUENCE:1
+STATUS:CANCELLED
+SUMMARY:Daily stuff
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
diff --git a/akonadi/calendar/tests/itip_data/invited_us_daily_cancel_recid01 \
b/akonadi/calendar/tests/itip_data/invited_us_daily_cancel_recid01 new file mode \
100644 index 0000000..058d8b3
--- /dev/null
+++ b/akonadi/calendar/tests/itip_data/invited_us_daily_cancel_recid01
@@ -0,0 +1,22 @@
+BEGIN:VCALENDAR
+PRODID:Zimbra-Calendar-Provider
+VERSION:2.0
+METHOD:CANCEL
+BEGIN:VEVENT
+UID:uosj936i6arrtl9c2i5r2mfuvg
+SUMMARY:Daily stuff
+ATTENDEE;RSVP=TRUE;PARTSTAT=ACCEPTED;ROLE=REQ-PARTICIPANT;
+ X-UID=140218344167648:mailto:their-email@dev.nul
+ATTENDEE;RSVP=TRUE:mailto:unittests@dev.nul
+ORGANIZER;mailto:their-email@dev.nul
+DTSTART:20131024T000000Z
+DTEND:20131024T010000Z
+STATUS:CANCELLED
+CLASS:PUBLIC
+TRANSP:OPAQUE
+RECURRENCE-ID:20131024T000000Z
+DTSTAMP:20131026T004419Z
+SEQUENCE:1
+DESCRIPTION:Foo
+END:VEVENT
+END:VCALENDAR
\ No newline at end of file
diff --git a/akonadi/calendar/tests/itip_data/invited_us_daily_update01 \
b/akonadi/calendar/tests/itip_data/invited_us_daily_update01 new file mode 100644
index 0000000..5a8f9bb
--- /dev/null
+++ b/akonadi/calendar/tests/itip_data/invited_us_daily_update01
@@ -0,0 +1,25 @@
+BEGIN:VCALENDAR
+PRODID:-//Unit-test
+VERSION:2.0
+CALSCALE:GREGORIAN
+METHOD:REQUEST
+BEGIN:VEVENT
+DTSTART:20131022T090000Z
+DTEND:20131022T100000Z
+RRULE:FREQ=DAILY
+DTSTAMP:20131023T175057Z
+ORGANIZER:mailto:their-email@dev.nul
+UID:uosj936i6arrtl9c2i5r2mfuvg
+ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;RSVP=TRUE
+ ;X-NUM-GUESTS=0:mailto:their-email@dev.nul
+ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=
+ TRUE;CN=unittests@dev.nul;X-NUM-GUESTS=0:mailto:unittests@dev.nul
+CREATED:20131023T175039Z
+DESCRIPTION:Foo
+LAST-MODIFIED:20131023T175057Z
+LOCATION:
+SEQUENCE:1
+STATUS:CONFIRMED
+SUMMARY:new-summary
+END:VEVENT
+END:VCALENDAR
diff --git a/akonadi/calendar/tests/itip_data/invited_us_daily_update_recid01 \
b/akonadi/calendar/tests/itip_data/invited_us_daily_update_recid01 new file mode \
100644 index 0000000..cfcff96
--- /dev/null
+++ b/akonadi/calendar/tests/itip_data/invited_us_daily_update_recid01
@@ -0,0 +1,26 @@
+BEGIN:VCALENDAR
+PRODID:-//Unit-test
+VERSION:2.0
+CALSCALE:GREGORIAN
+METHOD:REQUEST
+BEGIN:VEVENT
+DTSTART:20131023T090000Z
+DTEND:20131023T100000Z
+RRULE:FREQ=DAILY
+DTSTAMP:20131023T175057Z
+ORGANIZER:mailto:their-email@dev.nul
+UID:uosj936i6arrtl9c2i5r2mfuvg
+ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;RSVP=TRUE
+ ;X-NUM-GUESTS=0:mailto:their-email@dev.nul
+ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=
+ TRUE;CN=unittests@dev.nul;X-NUM-GUESTS=0:mailto:unittests@dev.nul
+CREATED:20131023T175039Z
+DESCRIPTION:Foo
+LAST-MODIFIED:20131023T175057Z
+RECURRENCE-ID:20131023T090000Z
+LOCATION:
+SEQUENCE:1
+STATUS:CONFIRMED
+SUMMARY:new-summary-for-second-occurrence
+END:VEVENT
+END:VCALENDAR
diff --git a/akonadi/calendar/tests/itip_data/invited_us_update01 \
b/akonadi/calendar/tests/itip_data/invited_us_update01 new file mode 100644
index 0000000..120b4bf
--- /dev/null
+++ b/akonadi/calendar/tests/itip_data/invited_us_update01
@@ -0,0 +1,23 @@
+BEGIN:VCALENDAR
+PRODID:-//Google Inc//Google Calendar 70.9054//EN
+VERSION:2.0
+CALSCALE:GREGORIAN
+METHOD:REQUEST
+BEGIN:VEVENT
+DTSTART:20131022T102000Z
+DTEND:20131022T112000Z
+DTSTAMP:20131019T224236Z
+ORGANIZER;CN=iamsergio@gmail.com:mailto:iamsergio@gmail.com
+UID:uosj936i6arrtl9c2i5r2mfuvg
+ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;RSVP=TRUE;X-NUM-GUESTS=0:mailto:their-email@dev.nul
 +ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN=sergio.martins@kdab.com;X-NUM-GUESTS=0:mailto:unittests@dev.nul
 +CREATED:20131019T224011Z
+DESCRIPTION:Random desc
+LAST-MODIFIED:20131019T224236Z
+LOCATION:
+SEQUENCE:1
+STATUS:CONFIRMED
+SUMMARY:new-summary
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
diff --git a/akonadi/calendar/tests/itiphandlertest.cpp \
b/akonadi/calendar/tests/itiphandlertest.cpp new file mode 100644
index 0000000..c601037
--- /dev/null
+++ b/akonadi/calendar/tests/itiphandlertest.cpp
@@ -0,0 +1,616 @@
+/*
+    Copyright (c) 2013 Sérgio Martins <iamsergio@gmail.com>
+
+    This library is free software; you can redistribute it and/or modify it
+    under the terms of the GNU Library General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    This library is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
+    License for more details.
+
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to the
+    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301, USA.
+*/
+
+#include "itiphandlertest.h"
+#include "helper.h"
+#include "../mailclient_p.h"
+#include "../fetchjobcalendar.h"
+
+#include <kcalcore/icalformat.h>
+#include <kcalcore/attendee.h>
+#include <akonadi/itemdeletejob.h>
+#include <akonadi/collectionfetchjob.h>
+#include <akonadi/collectionfetchscope.h>
+#include <akonadi/itemfetchscope.h>
+#include <akonadi/qtest_akonadi.h>
+
+#include <kcalcore/event.h>
+
+#include <QString>
+#include <QTestEventLoop>
+
+using namespace Akonadi;
+using namespace KCalCore;
+
+Q_DECLARE_METATYPE(Akonadi::IncidenceChanger::InvitationPolicy)
+Q_DECLARE_METATYPE(QList<Akonadi::IncidenceChanger::ChangeType>)
+Q_DECLARE_METATYPE(Akonadi::ITIPHandler::Result)
+Q_DECLARE_METATYPE(KCalCore::Attendee::PartStat)
+Q_DECLARE_METATYPE(QList<int>)
+
+static const char *s_ourEmail = "unittests@dev.nul"; // change also in \
kdepimlibs/akonadi/calendar/tests/unittestenv/kdehome/share/config +
+void ITIPHandlerTest::initTestCase()
+{
+    AkonadiTest::checkTestIsIsolated();
+    m_pendingItipMessageSignal = 0;
+    m_pendingIncidenceChangerSignal = 0;
+    MailClient::sRunningUnitTests = true;
+    m_itipHandler = 0;
+    m_changer = new IncidenceChanger(this);
+    m_changer->setHistoryEnabled(false);
+    m_changer->setGroupwareCommunication(true);
+    m_changer->setInvitationPolicy(IncidenceChanger::InvitationPolicySend); // don't \
show dialogs +
+    connect(m_changer, \
SIGNAL(createFinished(int,Akonadi::Item,Akonadi::IncidenceChanger::ResultCode,QString)),
 +            SLOT(onCreateFinished(int,Akonadi::Item,Akonadi::IncidenceChanger::ResultCode,QString)) \
); +
+    connect(m_changer, \
SIGNAL(deleteFinished(int,QVector<Akonadi::Item::Id>,Akonadi::IncidenceChanger::ResultCode,QString)),
 +            SLOT(onDeleteFinished(int,QVector<Akonadi::Item::Id>,Akonadi::IncidenceChanger::ResultCode,QString)) \
); +
+    connect(m_changer,SIGNAL(modifyFinished(int,Akonadi::Item,Akonadi::IncidenceChanger::ResultCode,QString)),
 +            SLOT(onModifyFinished(int,Akonadi::Item,Akonadi::IncidenceChanger::ResultCode,QString)) \
); +}
+
+void ITIPHandlerTest::testProcessITIPMessage_data()
+{
+    QTest::addColumn<QString>("data_filename");
+    QTest::addColumn<QString>("action");
+    QTest::addColumn<QString>("receiver");
+    QTest::addColumn<QString>("incidenceUid"); // uid of incidence in invitation
+    QTest::addColumn<Akonadi::ITIPHandler::Result>("expectedResult");
+    QTest::addColumn<int>("expectedNumIncidences");
+    QTest::addColumn<KCalCore::Attendee::PartStat>("expectedPartStat");
+
+    QString data_filename;
+    QString action = QLatin1String("accepted");
+    QString incidenceUid = QString::fromLatin1("uosj936i6arrtl9c2i5r2mfuvg");
+    QString receiver = QLatin1String(s_ourEmail);
+    Akonadi::ITIPHandler::Result expectedResult;
+    int expectedNumIncidences = 0;
+    KCalCore::Attendee::PartStat expectedPartStat;
+
+    //----------------------------------------------------------------------------------------------
 +    // Someone invited us to an event, and we accept
+    expectedResult = ITIPHandler::ResultSuccess;
+    data_filename = QLatin1String("invited_us");
+    expectedNumIncidences = 1;
+    expectedPartStat = KCalCore::Attendee::Accepted;
+    action = QLatin1String("accepted");
+    QTest::newRow("invited us1") << data_filename << action << receiver << \
incidenceUid +                                 << expectedResult
+                                 << expectedNumIncidences
+                                 << expectedPartStat;
+    //----------------------------------------------------------------------------------------------
 +    // Someone invited us to an event, and we accept conditionally
+    expectedResult = ITIPHandler::ResultSuccess;
+    data_filename = QLatin1String("invited_us");
+    expectedNumIncidences = 1;
+    expectedPartStat = KCalCore::Attendee::Tentative;
+    action = QLatin1String("tentative");
+    QTest::newRow("invited us2") << data_filename << action << receiver << \
incidenceUid +                                 << expectedResult
+                                 << expectedNumIncidences
+                                 << expectedPartStat;
+    //----------------------------------------------------------------------------------------------
 +    // Someone invited us to an event, we delegate it
+    expectedResult = ITIPHandler::ResultSuccess;
+    data_filename = QLatin1String("invited_us");
+
+    // The e-mail to the delegate is sent by kmail's text_calendar.cpp
+    expectedNumIncidences = 1;
+    expectedPartStat = KCalCore::Attendee::Delegated;
+    action = QLatin1String("delegated");
+    QTest::newRow("invited us3") << data_filename << action << receiver << \
incidenceUid +                                 << expectedResult
+                                 << expectedNumIncidences
+                                 << expectedPartStat;
+    //----------------------------------------------------------------------------------------------
 +    // Process a CANCEL without having the incidence in our calendar.
+    // itiphandler should return success and not error
+    expectedResult = ITIPHandler::ResultSuccess;
+    data_filename = QLatin1String("invited_us");
+    expectedNumIncidences = 0;
+    action = QLatin1String("cancel");
+    QTest::newRow("invited us4") << data_filename << action << receiver << \
incidenceUid +                                 << expectedResult
+                                 << expectedNumIncidences
+                                 << expectedPartStat;
+    //----------------------------------------------------------------------------------------------
 +    // Here we're testing an error case, where data is null.
+    expectedResult = ITIPHandler::ResultError;
+    expectedNumIncidences = 0;
+    action = QLatin1String("accepted");
+    QTest::newRow("invalid data") << QString() << action << receiver << incidenceUid
+                                  << expectedResult
+                                  << expectedNumIncidences
+                                  << expectedPartStat;
+    //----------------------------------------------------------------------------------------------
 +    // Testing invalid action
+    expectedResult = ITIPHandler::ResultError;
+    data_filename = QLatin1String("invitation_us");
+    expectedNumIncidences = 0;
+    action = QLatin1String("accepted");
+    QTest::newRow("invalid action") << data_filename << QString() << receiver << \
incidenceUid +                                    << expectedResult
+                                    << expectedNumIncidences
+                                    << expectedPartStat;
+    //----------------------------------------------------------------------------------------------
 +    // Test bug 235749
+    expectedResult = ITIPHandler::ResultSuccess;
+    data_filename = QLatin1String("bug235749");
+    expectedNumIncidences = 1;
+    expectedPartStat = KCalCore::Attendee::Accepted;
+    action = QLatin1String("accepted");
+    incidenceUid = QLatin1String("b6f0466a-8877-49d0-a4fc-8ee18ffd8e07"); // Don't \
change, hardcoded in data file +    QTest::newRow("bug 235749") << data_filename << \
action << receiver << incidenceUid +                                << expectedResult
+                                << expectedNumIncidences
+                                << expectedPartStat;
+    //----------------------------------------------------------------------------------------------
 +    // Test counterproposal without a UI delegat set
+    expectedResult = ITIPHandler::ResultError;
+    data_filename = QLatin1String("invited_us");
+    expectedNumIncidences = 0;
+    expectedPartStat = KCalCore::Attendee::Accepted;
+    action = QLatin1String("counter");
+    incidenceUid = QLatin1String("b6f0466a-8877-49d0-a4fc-8ee18ffd8e07");
+    QTest::newRow("counter error") << data_filename << action << receiver << \
incidenceUid +                                   << expectedResult
+                                   << expectedNumIncidences
+                                   << expectedPartStat;
+    //----------------------------------------------------------------------------------------------
 +}
+
+void ITIPHandlerTest::testProcessITIPMessage()
+{
+    QFETCH(QString, data_filename);
+    QFETCH(QString, action);
+    QFETCH(QString, receiver);
+    QFETCH(QString, incidenceUid);
+    QFETCH(Akonadi::ITIPHandler::Result, expectedResult);
+    QFETCH(int, expectedNumIncidences);
+    QFETCH(KCalCore::Attendee::PartStat, expectedPartStat);
+
+    MailClient::sUnitTestResults.clear();
+    createITIPHandler();
+
+    m_expectedResult = expectedResult;
+
+    QString iCalData = icalData(data_filename);
+    Akonadi::Item::List items;
+    processItip(iCalData, receiver, action, expectedNumIncidences, items);
+
+    if (expectedNumIncidences == 1) {
+        KCalCore::Incidence::Ptr incidence = \
items.first().payload<KCalCore::Incidence::Ptr>(); +        QVERIFY(incidence);
+        QCOMPARE(incidence->schedulingID(), incidenceUid);
+        QVERIFY(incidence->schedulingID() != incidence->uid());
+
+        KCalCore::Attendee::Ptr me = ourAttendee(incidence);
+        QVERIFY(me);
+        QCOMPARE(me->status(), expectedPartStat);
+    }
+
+    cleanup();
+}
+
+void ITIPHandlerTest::testProcessITIPMessages_data()
+{
+    QTest::addColumn<QStringList>("invitation_filenames"); // filename to create \
incidence (inputs) +    QTest::addColumn<QString>("expected_filename"); // filename \
with expected data   (reference) +    QTest::addColumn<QStringList>("actions"); // we \
must specify the METHOD. This is an ITipHandler API workaround, not sure why we must \
pass it as argument since it's already inside the icaldata. +    QStringList \
invitation_filenames; +    QString expected_filename;
+    QStringList actions;
+    actions << QLatin1String("accepted") << QLatin1String("accepted");
+
+    //----------------------------------------------------------------------------------------------
 +    // Someone invited us to an event, we accept, then organizer changes event, and \
we record update: +    invitation_filenames.clear();
+    invitation_filenames << QLatin1String("invited_us") << \
QLatin1String("invited_us_update01"); +    expected_filename = \
QLatin1String("expected_data/update1"); +    QTest::newRow("accept update") << \
invitation_filenames << expected_filename << actions; +    \
//----------------------------------------------------------------------------------------------
 +    // Someone invited us to an event, we accept, then organizer changes event, and \
we record update: +    invitation_filenames.clear();
+    invitation_filenames << QLatin1String("invited_us") << \
QLatin1String("invited_us_daily_update01"); +    expected_filename = \
QLatin1String("expected_data/update2"); +    QTest::newRow("accept recurringupdate") \
<< invitation_filenames << expected_filename << actions; +    \
//----------------------------------------------------------------------------------------------
 +    // We accept a recurring event, then the organizer changes the summary to the \
second instance (RECID) +    expected_filename = \
QLatin1String("expected_data/update3"); +    invitation_filenames.clear();
+    invitation_filenames << QLatin1String("invited_us_daily") << \
QLatin1String("invited_us_daily_update_recid01"); +    QTest::newRow("accept recid \
update") << invitation_filenames << expected_filename << actions; +    \
//----------------------------------------------------------------------------------------------
 +    // We accept a recurring event, then we accept a CANCEL with recuring-id.
+    // The result is that a exception with status CANCELLED should be created, and \
our main incidence +    // should not be touched
+    invitation_filenames.clear();
+    invitation_filenames << QLatin1String("invited_us_daily") << \
QLatin1String("invited_us_daily_cancel_recid01"); +    expected_filename = \
QLatin1String("expected_data/cancel1"); +    actions << QLatin1String("accepted") << \
QLatin1String("cancel"); +    QTest::newRow("accept recid cancel") << \
invitation_filenames << expected_filename << actions; +
+    //----------------------------------------------------------------------------------------------
 +}
+
+void ITIPHandlerTest::testProcessITIPMessages()
+{
+    QFETCH(QStringList, invitation_filenames);
+    QFETCH(QString, expected_filename);
+    QFETCH(QStringList, actions);
+
+    const QString receiver = QLatin1String(s_ourEmail);
+
+    MailClient::sUnitTestResults.clear();
+    createITIPHandler();
+
+    m_expectedResult = Akonadi::ITIPHandler::ResultSuccess;
+
+    for (int i=0; i<invitation_filenames.count(); i++) {
+        // First accept the invitation that creates the incidence:
+        QString iCalData = icalData(invitation_filenames.at(i));
+        Item::List items;
+        qDebug() << "Processing " << invitation_filenames.at(i);
+        processItip(iCalData, receiver, actions.at(i), -1, items);
+    }
+
+
+    QString expectedICalData = icalData(expected_filename);
+    KCalCore::MemoryCalendar::Ptr expectedCalendar = \
KCalCore::MemoryCalendar::Ptr(new KCalCore::MemoryCalendar(KDateTime::UTC)); +    \
KCalCore::ICalFormat format; +    format.fromString(expectedCalendar, \
expectedICalData); +    compareCalendars(expectedCalendar); // Here's where the cool \
and complex comparations are done +
+    cleanup();
+}
+
+void ITIPHandlerTest::testProcessITIPMessageCancel_data()
+{
+    QTest::addColumn<QString>("creation_data_filename"); // filename to create \
incidence +    QTest::addColumn<QString>("cancel_data_filename"); // filename with \
incidence cancelation +    QTest::addColumn<QString>("incidenceUid"); // uid of \
incidence in invitation +
+
+    QString creation_data_filename;
+    QString cancel_data_filename;
+    QString incidenceUid = QString::fromLatin1("uosj936i6arrtl9c2i5r2mfuvg");
+    //----------------------------------------------------------------------------------------------
 +    // Someone invited us to an event, we accept, then organizer cancels event
+    creation_data_filename = QLatin1String("invited_us");
+    cancel_data_filename = QLatin1String("invited_us_cancel01");
+
+    QTest::newRow("cancel1") << creation_data_filename << cancel_data_filename
+                             << incidenceUid;
+    //----------------------------------------------------------------------------------------------
 +    // Someone invited us to daily event, we accept, then organizer cancels the \
whole recurrence series +    creation_data_filename = \
QLatin1String("invited_us_daily"); +    cancel_data_filename = \
QLatin1String("invited_us_daily_cancel01"); +
+    QTest::newRow("cancel_daily") << creation_data_filename << cancel_data_filename
+                                  << incidenceUid;
+    //----------------------------------------------------------------------------------------------
 +}
+
+void ITIPHandlerTest::testProcessITIPMessageCancel()
+{
+    QFETCH(QString, creation_data_filename);
+    QFETCH(QString, cancel_data_filename);
+    QFETCH(QString, incidenceUid);
+
+    const QString receiver = QLatin1String(s_ourEmail);
+    MailClient::sUnitTestResults.clear();
+    createITIPHandler();
+
+    m_expectedResult = Akonadi::ITIPHandler::ResultSuccess;
+
+    // First accept the invitation that creates the incidence:
+    QString iCalData = icalData(creation_data_filename);
+    Item::List items;
+    processItip(iCalData, receiver, QLatin1String("accepted"), 1, items);
+
+    KCalCore::Incidence::Ptr incidence = \
items.first().payload<KCalCore::Incidence::Ptr>(); +    QVERIFY(incidence);
+
+    // good, now accept the invitation that has the CANCEL
+    iCalData = icalData(cancel_data_filename);
+    processItip(iCalData, receiver, QLatin1String("accepted"), 0, items);
+}
+
+void ITIPHandlerTest::testOutgoingInvitations_data()
+{
+    QTest::addColumn<Akonadi::Item>("item"); // existing incidence that will be \
target of creation, deletion or modification +    \
QTest::addColumn<Akonadi::IncidenceChanger::ChangeType>("changeType"); // creation, \
deletion, modification +    QTest::addColumn<int>("expectedEmailCount");
+    QTest::addColumn<IncidenceChanger::InvitationPolicy>("invitationPolicy");
+
+    Akonadi::Item item;
+    KCalCore::Incidence::Ptr incidence;
+    IncidenceChanger::ChangeType changeType;
+    const IncidenceChanger::InvitationPolicy invitationPolicyAsk     = \
IncidenceChanger::InvitationPolicyAsk; +    const IncidenceChanger::InvitationPolicy \
invitationPolicySend     = IncidenceChanger::InvitationPolicySend; +    const \
IncidenceChanger::InvitationPolicy invitationPolicyDontSend = \
IncidenceChanger::InvitationPolicyDontSend; +    int expectedEmailCount = 0;
+    Q_UNUSED(invitationPolicyAsk);
+
+    const QString ourEmail     = QLatin1String(s_ourEmail);
+    const Attendee::Ptr us = Attendee::Ptr(new Attendee(QString(), ourEmail));
+    const Attendee::Ptr mia = Attendee::Ptr(new Attendee(QLatin1String("Mia \
Wallace"), QLatin1String("mia@dev.nul"))); +    const Attendee::Ptr vincent = \
Attendee::Ptr(new Attendee(QLatin1String("Vincent"), \
QLatin1String("vincent@dev.nul"))); +    const Attendee::Ptr jules = \
Attendee::Ptr(new Attendee(QLatin1String("Jules"), QLatin1String("jules@dev.nul"))); \
+    const QString uid = QLatin1String("random-uid-123"); +
+    //----------------------------------------------------------------------------------------------
 +    // Creation. We are organizer. We invite another person.
+    changeType = IncidenceChanger::ChangeTypeCreate;
+    item = generateIncidence(uid, /**organizer=*/ourEmail);
+    incidence = item.payload<KCalCore::Incidence::Ptr>();
+    incidence->addAttendee(vincent);
+    incidence->addAttendee(jules);
+    expectedEmailCount = 1;
+    QTest::newRow("Creation. We organize.") << item << changeType << \
expectedEmailCount << invitationPolicySend; +    \
//----------------------------------------------------------------------------------------------
 +    // Creation. We are organizer. We invite another person. But we choose not to \
send invitation e-mail. +    changeType = IncidenceChanger::ChangeTypeCreate;
+    item = generateIncidence(uid, /**organizer=*/ourEmail);
+    incidence = item.payload<KCalCore::Incidence::Ptr>();
+    incidence->addAttendee(vincent);
+    incidence->addAttendee(jules);
+    expectedEmailCount = 0;
+    QTest::newRow("Creation. We organize.2") << item << changeType << \
expectedEmailCount << invitationPolicyDontSend; +    \
//----------------------------------------------------------------------------------------------
 +    // We delete an event that we organized, and has attendees, that will be \
notified. +    changeType = IncidenceChanger::ChangeTypeDelete;
+    item = generateIncidence(uid, /**organizer=*/ourEmail);
+    incidence = item.payload<KCalCore::Incidence::Ptr>();
+    incidence->addAttendee(vincent);
+    incidence->addAttendee(jules);
+    expectedEmailCount = 1;
+    QTest::newRow("Deletion. We organized.") << item << changeType << \
expectedEmailCount << invitationPolicySend; +    \
//----------------------------------------------------------------------------------------------
 +    // We delete an event that we organized, and has attendees. We won't send \
e-mail notifications. +    changeType = IncidenceChanger::ChangeTypeDelete;
+    item = generateIncidence(uid, /**organizer=*/ourEmail);
+    incidence = item.payload<KCalCore::Incidence::Ptr>();
+    incidence->addAttendee(vincent);
+    incidence->addAttendee(jules);
+    expectedEmailCount = 0;
+    QTest::newRow("Deletion. We organized.2") << item << changeType << \
expectedEmailCount << invitationPolicyDontSend; +    \
//----------------------------------------------------------------------------------------------
 +    // We delete an event that we organized, and has attendees, who will be \
notified. +    changeType = IncidenceChanger::ChangeTypeModify;
+    item = generateIncidence(uid, /**organizer=*/ourEmail);
+    incidence = item.payload<KCalCore::Incidence::Ptr>();
+    incidence->addAttendee(vincent);
+    incidence->addAttendee(jules);
+    expectedEmailCount = 1;
+    QTest::newRow("Modification. We organizd.") << item << changeType << \
expectedEmailCount << invitationPolicySend; +    \
//----------------------------------------------------------------------------------------------
 +    // We delete an event that we organized, and has attendees, who wont be \
notified. +    changeType = IncidenceChanger::ChangeTypeModify;
+    item = generateIncidence(uid, /**organizer=*/ourEmail);
+    incidence = item.payload<KCalCore::Incidence::Ptr>();
+    incidence->addAttendee(vincent); // TODO: test that all attendees got the e-mail
+    incidence->addAttendee(jules);
+    expectedEmailCount = 0;
+    QTest::newRow("Modification. We organizd.2") << item << changeType << \
expectedEmailCount << invitationPolicyDontSend; +    \
//----------------------------------------------------------------------------------------------
 +    // We delete an event which we're not the organizer of. Organizer gets REPLY \
with PartState=Declined +    changeType = IncidenceChanger::ChangeTypeDelete;
+    item = generateIncidence(uid, /**organizer=*/mia->email());
+    incidence = item.payload<KCalCore::Incidence::Ptr>();
+    incidence->addAttendee(vincent);
+    incidence->addAttendee(jules);
+    us->setStatus(Attendee::Accepted); // TODO: Test without accepted status
+    incidence->addAttendee(us); // TODO: test that attendees didn't receive the \
REPLY +    expectedEmailCount = 1; // REPLY is always sent, there are no dialogs to \
control this. Dialogs only control REQUEST and CANCEL. Bug or feature ? +    \
QTest::newRow("Deletion. We didnt organize.") << item << changeType << \
expectedEmailCount << invitationPolicyDontSend; +    \
//----------------------------------------------------------------------------------------------
 +    // We delete an event which we're not the organizer of. Organizer gets REPLY \
with PartState=Declined +    changeType = IncidenceChanger::ChangeTypeDelete;
+    item = generateIncidence(uid, /**organizer=*/mia->email());
+    incidence = item.payload<KCalCore::Incidence::Ptr>();
+    incidence->addAttendee(vincent);
+    incidence->addAttendee(jules); // TODO: test that attendees didn't receive the \
REPLY +    us->setStatus(Attendee::Accepted); // TODO: Test without accepted status
+    incidence->addAttendee(us);
+    expectedEmailCount = 1;
+    QTest::newRow("Deletion. We didnt organize.2") << item << changeType << \
expectedEmailCount << invitationPolicySend; +    \
//----------------------------------------------------------------------------------------------
 +}
+
+void ITIPHandlerTest::testOutgoingInvitations()
+{
+    QFETCH(Akonadi::Item, item);
+    QFETCH(IncidenceChanger::ChangeType, changeType);
+    QFETCH(int, expectedEmailCount);
+    QFETCH(IncidenceChanger::InvitationPolicy, invitationPolicy);
+    KCalCore::Incidence::Ptr incidence = item.payload<KCalCore::Incidence::Ptr>();
+
+    m_pendingIncidenceChangerSignal = 1;
+    MailClient::sUnitTestResults.clear();
+    m_changer->setInvitationPolicy(invitationPolicy);
+
+    switch(changeType) {
+    case IncidenceChanger::ChangeTypeCreate:
+        m_changer->createIncidence(incidence, mCollection);
+        waitForIt();
+        QCOMPARE(MailClient::sUnitTestResults.count(), expectedEmailCount);
+        break;
+    case IncidenceChanger::ChangeTypeModify: {
+        // Create if first, so we have something to modify
+        m_changer->setGroupwareCommunication(false); // we disable groupware because \
creating an incidence which we're not the organizer of is not permitted. +        \
m_changer->createIncidence(incidence, mCollection); +        waitForIt();
+        m_changer->setGroupwareCommunication(true);
+        QCOMPARE(MailClient::sUnitTestResults.count(), 0);
+        QVERIFY(mLastInsertedItem.isValid());
+        m_pendingIncidenceChangerSignal = 1;
+        Incidence::Ptr oldIncidence = Incidence::Ptr(incidence->clone());
+        incidence->setSummary(QLatin1String("the-new-summary"));
+        int changeId = m_changer->modifyIncidence(mLastInsertedItem, oldIncidence);
+        QVERIFY(changeId != 1);
+        waitForIt();
+        QCOMPARE(MailClient::sUnitTestResults.count(), expectedEmailCount);
+    }
+        break;
+    case IncidenceChanger::ChangeTypeDelete:
+        // Create if first, so we have something to delete
+        m_changer->setGroupwareCommunication(false);
+        m_changer->createIncidence(incidence, mCollection);
+        waitForIt();
+        m_changer->setGroupwareCommunication(true);
+        QCOMPARE(MailClient::sUnitTestResults.count(), 0);
+
+        QVERIFY(mLastInsertedItem.isValid());
+        m_pendingIncidenceChangerSignal = 1;
+        m_changer->deleteIncidence(mLastInsertedItem);
+        waitForIt();
+        QCOMPARE(MailClient::sUnitTestResults.count(), expectedEmailCount);
+        break;
+    default:
+        Q_ASSERT(false);
+    }
+
+}
+
+void ITIPHandlerTest::cleanup()
+{
+    Akonadi::Item::List items = calendarItems();
+    foreach (const Akonadi::Item &item, items) {
+        ItemDeleteJob *job = new ItemDeleteJob(item);
+        AKVERIFYEXEC(job);
+    }
+
+    delete m_itipHandler;
+    m_itipHandler = 0;
+}
+
+void ITIPHandlerTest::createITIPHandler()
+{
+    m_itipHandler = new Akonadi::ITIPHandler();
+    m_itipHandler->setShowDialogsOnError(false);
+    connect(m_itipHandler, \
SIGNAL(iTipMessageProcessed(Akonadi::ITIPHandler::Result,QString)), +            \
SLOT(oniTipMessageProcessed(Akonadi::ITIPHandler::Result,QString)) ); +}
+
+QString ITIPHandlerTest::icalData(const QString &data_filename)
+{
+    QString absolutePath = QLatin1String(ITIP_DATA_DIR) + QLatin1Char('/') + \
data_filename; +    return QString::fromLatin1(readFile(absolutePath));
+}
+
+void ITIPHandlerTest::processItip(const QString &icaldata, const QString &receiver,
+                                  const QString &action, int expectedNumIncidences,
+                                  Akonadi::Item::List &items)
+{
+    items.clear();
+    m_pendingItipMessageSignal = 1;
+    m_itipHandler->processiTIPMessage(receiver, icaldata, action);
+    waitForIt();
+
+    // 0 e-mails are sent because the status update e-mail is sent by
+    // kmail's text_calendar.cpp.
+    QCOMPARE(MailClient::sUnitTestResults.count(), 0);
+
+    items = calendarItems();
+
+    if (expectedNumIncidences != -1) {
+        QCOMPARE(items.count(), expectedNumIncidences);
+    }
+}
+
+Attendee::Ptr ITIPHandlerTest::ourAttendee(const KCalCore::Incidence::Ptr \
&incidence) const +{
+    KCalCore::Attendee::List attendees = incidence->attendees();
+    KCalCore::Attendee::Ptr me;
+    foreach (const KCalCore::Attendee::Ptr &attendee, attendees) {
+        if (attendee->email() == QLatin1String(s_ourEmail)) {
+            me = attendee;
+            break;
+        }
+    }
+
+    return me;
+}
+
+void ITIPHandlerTest::oniTipMessageProcessed(ITIPHandler::Result result, const \
QString &errorMessage) +{
+    if (result != ITIPHandler::ResultSuccess && result != m_expectedResult) {
+        qDebug() << "ITIPHandlerTest::oniTipMessageProcessed() error = " << \
errorMessage; +    }
+
+    m_pendingItipMessageSignal--;
+    QVERIFY(m_pendingItipMessageSignal >= 0);
+    if (m_pendingItipMessageSignal == 0) {
+        stopWaiting();
+    }
+
+    QCOMPARE(m_expectedResult, result);
+}
+
+void ITIPHandlerTest::onCreateFinished(int changeId, const Item &item,
+                                       IncidenceChanger::ResultCode resultCode,
+                                       const QString &errorString)
+{
+    Q_UNUSED(changeId);
+    Q_UNUSED(errorString);
+    mLastInsertedItem = item;
+    QCOMPARE(resultCode, IncidenceChanger::ResultCodeSuccess);
+    m_pendingIncidenceChangerSignal--;
+    QVERIFY(m_pendingIncidenceChangerSignal >= 0);
+    if (m_pendingIncidenceChangerSignal == 0) {
+        stopWaiting();
+    }
+}
+
+void ITIPHandlerTest::onDeleteFinished(int changeId, const QVector<Entity::Id> \
&deletedIds, +                                       IncidenceChanger::ResultCode \
resultCode, +                                       const QString &errorString)
+{
+    Q_UNUSED(changeId);
+    Q_UNUSED(errorString);
+    Q_UNUSED(deletedIds);
+    QCOMPARE(resultCode, IncidenceChanger::ResultCodeSuccess);
+    m_pendingIncidenceChangerSignal--;
+    QVERIFY(m_pendingIncidenceChangerSignal >= 0);
+    if (m_pendingIncidenceChangerSignal == 0) {
+        stopWaiting();
+    }
+}
+
+void ITIPHandlerTest::onModifyFinished(int changeId, const Item &item,
+                                       IncidenceChanger::ResultCode resultCode,
+                                       const QString &errorString)
+{
+    Q_UNUSED(changeId);
+    Q_UNUSED(errorString);
+    Q_UNUSED(item);
+
+    QCOMPARE(resultCode, IncidenceChanger::ResultCodeSuccess);
+    m_pendingIncidenceChangerSignal--;
+    QVERIFY(m_pendingIncidenceChangerSignal >= 0);
+    if (m_pendingIncidenceChangerSignal == 0) {
+        stopWaiting();
+    }
+}
+
+QTEST_AKONADIMAIN(ITIPHandlerTest, GUI)
diff --git a/akonadi/calendar/tests/itiphandlertest.h \
b/akonadi/calendar/tests/itiphandlertest.h new file mode 100644
index 0000000..df3844c
--- /dev/null
+++ b/akonadi/calendar/tests/itiphandlertest.h
@@ -0,0 +1,92 @@
+/*
+    Copyright (c) 2013 Sérgio Martins <iamsergio@gmail.com>
+
+    This library is free software; you can redistribute it and/or modify it
+    under the terms of the GNU Library General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    This library is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
+    License for more details.
+
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to the
+    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301, USA.
+*/
+
+#ifndef ITIPHANDLER_TEST_H
+#define ITIPHANDLER_TEST_H
+
+#include "../incidencechanger.h"
+#include "../itiphandler.h"
+#include "unittestbase.h"
+
+#include <akonadi/collection.h>
+#include <akonadi/item.h>
+
+#include <QObject>
+#include <QHash>
+
+
+class ITIPHandlerTest : public UnitTestBase
+{
+    Q_OBJECT
+
+private Q_SLOTS:
+    void initTestCase();
+
+    void testProcessITIPMessages_data();
+    void testProcessITIPMessages();
+
+    // Deprecated methods, use testProcessITIPMessages() for new stuff
+    void testProcessITIPMessage_data();
+    void testProcessITIPMessage();
+
+    // Deprecated methods do test CANCEL.
+    void testProcessITIPMessageCancel_data();
+    void testProcessITIPMessageCancel();
+
+    // These ones don't have to do with kmail. It's when doing a modification, itip \
REQUESTs are sent. +    // Also tests cases where we're not the organizer.
+    void testOutgoingInvitations_data();
+    void testOutgoingInvitations();
+
+private:
+    void waitForSignals();
+    void cleanup();
+    void createITIPHandler();
+    QString icalData(const QString &filename);
+    void processItip(const QString &icaldata, const QString &receiver,
+                     const QString &action, int expectedNumIncidences,
+                     Akonadi::Item::List &items);
+    KCalCore::Attendee::Ptr ourAttendee(const KCalCore::Incidence::Ptr &incidence) \
const; +
+public Q_SLOTS:
+    void oniTipMessageProcessed(Akonadi::ITIPHandler::Result result,
+                                const QString &errorMessage);
+
+    void onCreateFinished(int changeId, const Akonadi::Item &item,
+                          Akonadi::IncidenceChanger::ResultCode resultCode,
+                          const QString &errorString);
+
+    void onDeleteFinished(int changeId, const QVector<Akonadi::Item::Id> \
&deletedIds, +                          Akonadi::IncidenceChanger::ResultCode \
resultCode, +                          const QString &errorMessage);
+
+    void onModifyFinished(int changeId, const Akonadi::Item &item,
+                          Akonadi::IncidenceChanger::ResultCode resultCode,
+                          const QString &errorString);
+
+private:
+    int m_pendingItipMessageSignal;
+    int m_pendingIncidenceChangerSignal;
+    Akonadi::Item mLastInsertedItem;
+    Akonadi::ITIPHandler::Result m_expectedResult;
+    Akonadi::ITIPHandler *m_itipHandler;
+    Akonadi::IncidenceChanger *m_changer;
+};
+
+#endif
diff --git a/akonadi/calendar/tests/mailclienttest.cpp \
b/akonadi/calendar/tests/mailclienttest.cpp index 425b231..2231401 100644
--- a/akonadi/calendar/tests/mailclienttest.cpp
+++ b/akonadi/calendar/tests/mailclienttest.cpp
@@ -19,19 +19,20 @@
 
 // mailclient_p.cpp isn't exported so we include it directly.
 
-#define MAILCLIENTTEST_UNITTEST
-#include "../mailclient_p.cpp"
-#include "../moc_mailclient_p.cpp"
+#include "../mailclient_p.h"
 
 #include <kcalcore/incidence.h>
 #include <kcalcore/freebusy.h>
 #include <mailtransport/messagequeuejob.h>
+#include <kpimidentities/identity.h>
 
 #include <akonadi/qtest_akonadi.h>
 
 #include <QTestEventLoop>
 #include <QtCore/QObject>
 
+static const char *s_ourEmail = "unittests@dev.nul"; // change also in \
kdepimlibs/akonadi/calendar/tests/unittestenv/kdehome/share/config +
 using namespace Akonadi;
 
 Q_DECLARE_METATYPE( KPIMIdentities::Identity )
@@ -55,6 +56,7 @@ private slots:
 
     mPendingSignals = 0;
     mMailClient = new MailClient( this );
+    mMailClient->sRunningUnitTests = true;
     mLastResult = MailClient::ResultSuccess;
     connect( mMailClient, SIGNAL(finished(Akonadi::MailClient::Result,QString)),
              SLOT(handleFinished(Akonadi::MailClient::Result,QString)) );
@@ -114,7 +116,7 @@ private slots:
     incidence->addAttendee( attendee );
     incidence->setOrganizer( organizer );
     expectedResult = MailClient::ResultSuccess;
-    toList << QLatin1String( "name1 <test@foo.org>" );
+    toList << QLatin1String( "test@foo.org" );
     QTest::newRow("One attendee") << incidence << identity << bccMe << attachment << \
                transport
                                   << expectedResult << expectedTransportId << \
expectedFrom  << toList << toCcList << toBccList;
@@ -142,11 +144,11 @@ private slots:
     expectedResult = MailClient::ResultSuccess;
     // Should default to the default transport
     toBccList.clear();
-    toBccList << QLatin1String( "Organizer <unittests@dev.nul>" );
-    QTest::newRow("Invalid transport") << incidence << identity << /*bccMe*/true << \
                attachment
-                                       << transport  << expectedResult
-                                       << expectedTransportId << expectedFrom
-                                       << toList << toCcList << toBccList;
+    toBccList << QLatin1String( "unittests@dev.nul" );
+    QTest::newRow("Test bcc") << incidence << identity << /*bccMe*/true << \
attachment +                                           << transport  << \
expectedResult +                                           << expectedTransportId << \
expectedFrom +                                           << toList << toCcList << \
                toBccList;
     //----------------------------------------------------------------------------------------------
  // Test CC list
     attendee = KCalCore::Attendee::Ptr ( new KCalCore::Attendee( QLatin1String( \
"name1" ), @@ -167,15 +169,15 @@ private slots:
     expectedResult = MailClient::ResultSuccess;
     // Should default to the default transport
     toBccList.clear();
-    toBccList << QLatin1String( "Organizer <unittests@dev.nul>" );
+    toBccList << QLatin1String( "unittests@dev.nul" );
 
     toCcList.clear();
-    toCcList << QLatin1String( "opt <optional@foo.org>" )
-             << QLatin1String( "non <non@foo.org>" );
-    QTest::newRow("Invalid transport") << incidence << identity << /*bccMe*/true << \
                attachment
-                                       << transport  << expectedResult
-                                       << expectedTransportId << expectedFrom
-                                       << toList << toCcList << toBccList;
+    toCcList << QLatin1String( "optional@foo.org" )
+             << QLatin1String( "non@foo.org" );
+    QTest::newRow("Test cc") << incidence << identity << /*bccMe*/true << attachment
+                                          << transport  << expectedResult
+                                          << expectedTransportId << expectedFrom
+                                          << toList << toCcList << toBccList;
   }
 
   void testMailAttendees()
@@ -191,6 +193,7 @@ private slots:
     QFETCH( QStringList, expectedToList  );
     QFETCH( QStringList, expectedCcList  );
     QFETCH( QStringList, expectedBccList );
+    mMailClient->sUnitTestResults.clear();
 
     mPendingSignals = 1;
     mMailClient->mailAttendees( incidence, identity, bccMe, attachment, transport );
@@ -202,18 +205,23 @@ private slots:
       QVERIFY( false );
     }
 
+    UnitTestResult unitTestResult;
+    if ( mMailClient->sUnitTestResults.isEmpty() ) {
+        qDebug() << "mail results are empty";
+    } else {
+        unitTestResult = mMailClient->sUnitTestResults.first();
+    }
 
-    if ( expectedTransportId != -1 &&
-         mMailClient->mUnitTestResult.transportId != expectedTransportId ) {
-      qDebug() << "got " << mMailClient->mUnitTestResult.transportId
+    if ( expectedTransportId != -1 && unitTestResult.transportId != \
expectedTransportId ) { +      qDebug() << "got " << unitTestResult.transportId
                << "; expected=" << expectedTransportId;
       QVERIFY( false );
     }
 
-    QCOMPARE( mMailClient->mUnitTestResult.from, expectedFrom );
-    QCOMPARE( mMailClient->mUnitTestResult.to, expectedToList );
-    QCOMPARE( mMailClient->mUnitTestResult.cc, expectedCcList );
-    QCOMPARE( mMailClient->mUnitTestResult.bcc, expectedBccList );
+    QCOMPARE( unitTestResult.from, expectedFrom );
+    QCOMPARE( unitTestResult.to, expectedToList );
+    QCOMPARE( unitTestResult.cc, expectedCcList );
+    QCOMPARE( unitTestResult.bcc, expectedBccList );
   }
 
   void testMailOrganizer_data()
@@ -234,7 +242,7 @@ private slots:
 
     KCalCore::IncidenceBase::Ptr incidence( new KCalCore::Event() );
     KPIMIdentities::Identity identity;
-    const QString from = QLatin1String( "from@kde.org" );
+    const QString from = QLatin1String( s_ourEmail );
     bool bccMe;
     QString attachment;
     QString subject = QLatin1String( "subject1" );
@@ -247,7 +255,7 @@ private slots:
     incidence->setOrganizer( organizer );
 
     QStringList toList;
-    toList << QLatin1String( "Organizer <unittests@dev.nul>" );
+    toList << QLatin1String( "unittests@dev.nul" );
     QStringList toBccList;
     QString expectedSubject;
     //----------------------------------------------------------------------------------------------
 @@ -279,18 +287,21 @@ private slots:
     QFETCH( QStringList, expectedToList  );
     QFETCH( QStringList, expectedBccList );
     QFETCH( QString, expectedSubject );
+    mMailClient->sUnitTestResults.clear();
 
     mPendingSignals = 1;
     mMailClient->mailOrganizer( incidence, identity, from, bccMe, attachment, \
subject, transport );  waitForSignals();
     QCOMPARE( mLastResult, expectedResult );
+
+    UnitTestResult unitTestResult = mMailClient->sUnitTestResults.first();
     if ( expectedTransportId != -1 )
-      QCOMPARE( mMailClient->mUnitTestResult.transportId, expectedTransportId );
+      QCOMPARE( unitTestResult.transportId, expectedTransportId );
 
-    QCOMPARE( mMailClient->mUnitTestResult.from, expectedFrom );
-    QCOMPARE( mMailClient->mUnitTestResult.to, expectedToList );
-    QCOMPARE( mMailClient->mUnitTestResult.bcc, expectedBccList );
-    QCOMPARE( mMailClient->mUnitTestResult.message->subject()->asUnicodeString(), \
expectedSubject ); +    QCOMPARE( unitTestResult.from, expectedFrom );
+    QCOMPARE( unitTestResult.to, expectedToList );
+    QCOMPARE( unitTestResult.bcc, expectedBccList );
+    QCOMPARE( unitTestResult.message->subject()->asUnicodeString(), expectedSubject \
);  }
 
   void testMailTo_data()
@@ -310,9 +321,9 @@ private slots:
 
     KCalCore::IncidenceBase::Ptr incidence( new KCalCore::Event() );
     KPIMIdentities::Identity identity;
-    const QString from = QLatin1String( "from@kde.org" );
+    const QString from = QLatin1String( s_ourEmail );
     bool bccMe;
-    const QString recipients = QLatin1String( "Organizer <unittests@dev.nul>" );
+    const QString recipients = QLatin1String( "unittests@dev.nul" );
     QString attachment;
     QString transport;
     MailClient::Result expectedResult = MailClient::ResultSuccess;
@@ -321,7 +332,7 @@ private slots:
     KCalCore::Person::Ptr organizer( new KCalCore::Person( QLatin1String( \
                "Organizer" ),
                                                            QLatin1String( \
"unittests@dev.nul" ) ) );  QStringList toList;
-    toList << QLatin1String( "Organizer <unittests@dev.nul>" );
+    toList << QLatin1String( s_ourEmail );
     QStringList toBccList;
     //----------------------------------------------------------------------------------------------
                
     QTest::newRow("test1") << incidence << identity << from << bccMe << recipients \
<< attachment @@ -343,17 +354,19 @@ private slots:
     QFETCH( QString, expectedFrom );
     QFETCH( QStringList, expectedToList  );
     QFETCH( QStringList, expectedBccList );
+    mMailClient->sUnitTestResults.clear();
 
     mPendingSignals = 1;
     mMailClient->mailTo( incidence, identity, from, bccMe, recipients, attachment, \
transport );  waitForSignals();
     QCOMPARE( mLastResult, expectedResult );
+    UnitTestResult unitTestResult = mMailClient->sUnitTestResults.first();
     if ( expectedTransportId != -1 )
-      QCOMPARE( mMailClient->mUnitTestResult.transportId, expectedTransportId );
+      QCOMPARE( unitTestResult.transportId, expectedTransportId );
 
-    QCOMPARE( mMailClient->mUnitTestResult.from, expectedFrom );
-    QCOMPARE( mMailClient->mUnitTestResult.to, expectedToList );
-    QCOMPARE( mMailClient->mUnitTestResult.bcc, expectedBccList );
+    QCOMPARE( unitTestResult.from, expectedFrom );
+    QCOMPARE( unitTestResult.to, expectedToList );
+    QCOMPARE( unitTestResult.bcc, expectedBccList );
   }
 
   void handleFinished( Akonadi::MailClient::Result result, const QString \
                &errorMessage )
diff --git a/akonadi/calendar/tests/todopurgertest.cpp \
b/akonadi/calendar/tests/todopurgertest.cpp new file mode 100644
index 0000000..c568d32
--- /dev/null
+++ b/akonadi/calendar/tests/todopurgertest.cpp
@@ -0,0 +1,207 @@
+/*
+    Copyright (c) 2013 Sérgio Martins <iamsergio@gmail.com>
+
+    This library is free software; you can redistribute it and/or modify it
+    under the terms of the GNU Library General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    This library is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
+    License for more details.
+
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to the
+    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301, USA.
+*/
+
+#include "todopurgertest.h"
+
+#include "../etmcalendar.h"
+#include "../todopurger.h"
+#include <akonadi/itemcreatejob.h>
+#include <akonadi/qtest_akonadi.h>
+#include <akonadi/collectionfetchjob.h>
+#include <akonadi/collectionfetchscope.h>
+#include <akonadi/collectionmodifyjob.h>
+#include <akonadi/itemdeletejob.h>
+#include <akonadi/itemmodifyjob.h>
+#include <KCheckableProxyModel>
+
+#include <QTestEventLoop>
+
+using namespace Akonadi;
+using namespace KCalCore;
+
+Q_DECLARE_METATYPE( QSet<QByteArray> )
+
+void TodoPurgerTest::createTodo(const QString &uid, const QString &parentUid, bool \
completed, bool recurring ) +{
+    Item item;
+    item.setMimeType(Todo::todoMimeType());
+    Todo::Ptr todo = Todo::Ptr(new Todo());
+    todo->setUid(uid);
+
+    const KDateTime today = KDateTime::currentDateTime(KDateTime::UTC);
+    const KDateTime yesterday = today.addDays(-1);
+
+    todo->setDtStart(yesterday);
+    todo->setRelatedTo(parentUid);
+
+    if (recurring)
+        todo->recurrence()->setDaily(1);
+
+    if (recurring && completed) {
+        todo->setCompleted(today);
+    } else {
+        todo->setCompleted(completed);
+    }
+
+    todo->setSummary(QLatin1String("summary"));
+
+
+    item.setPayload<KCalCore::Incidence::Ptr>(todo);
+    ItemCreateJob *job = new ItemCreateJob(item, m_collection, this);
+    m_pendingCreations++;
+    AKVERIFYEXEC(job);
+}
+
+void TodoPurgerTest::fetchCollection()
+{
+    CollectionFetchJob *job = new CollectionFetchJob(Collection::root(),
+                                                     CollectionFetchJob::Recursive,
+                                                     this);
+    // Get list of collections
+    job->fetchScope().setContentMimeTypes(QStringList() << \
QLatin1String("application/x-vnd.akonadi.calendar.todo")); +    AKVERIFYEXEC(job);
+
+    // Find our collection
+    Collection::List collections = job->collections();
+    QVERIFY(!collections.isEmpty());
+    m_collection = collections.first();
+
+    QVERIFY(m_collection.isValid());
+}
+
+void TodoPurgerTest::initTestCase()
+{
+    AkonadiTest::checkTestIsIsolated();
+
+    qRegisterMetaType<QSet<QByteArray> >("QSet<QByteArray>");
+    fetchCollection();
+
+    m_pendingCreations = 0;
+    m_pendingDeletions = 0;
+    m_calendar = new ETMCalendar();
+    m_calendar->registerObserver(this);
+    m_todoPurger = new TodoPurger(this);
+
+    connect(m_todoPurger, SIGNAL(todosPurged(bool,int,int)), \
SLOT(onTodosPurged(bool,int,int))); +
+    connect(m_calendar, SIGNAL(collectionsAdded(Akonadi::Collection::List)),
+            &QTestEventLoop::instance(), SLOT(exitLoop()));
+
+    // Wait for the collection
+    QTestEventLoop::instance().enterLoop(10);
+    QVERIFY(!QTestEventLoop::instance().timeout());
+
+    KCheckableProxyModel *checkable = m_calendar->checkableProxyModel();
+    const QModelIndex firstIndex = checkable->index(0, 0);
+    QVERIFY(firstIndex.isValid());
+    checkable->setData(firstIndex, Qt::Checked, Qt::CheckStateRole);
+}
+
+void TodoPurgerTest::cleanupTestCase()
+{
+    delete m_calendar;
+}
+
+void TodoPurgerTest::testPurge()
+{
+    createTree();
+
+    m_pendingDeletions = 8;
+    m_pendingPurgeSignal = true;
+
+    m_todoPurger->purgeCompletedTodos();
+
+    // Wait for deletions and purged signal
+    QTestEventLoop::instance().enterLoop(10);
+    QVERIFY(!QTestEventLoop::instance().timeout());
+
+    QCOMPARE(m_numDeleted, 10);
+    QCOMPARE(m_numIgnored, 2);
+}
+
+void TodoPurgerTest::calendarIncidenceAdded(const Incidence::Ptr &)
+{
+    --m_pendingCreations;
+    if (m_pendingCreations == 0) {
+        QTestEventLoop::instance().exitLoop();
+    }
+}
+
+void TodoPurgerTest::calendarIncidenceDeleted(const Incidence::Ptr &)
+{
+    --m_pendingDeletions;
+    if (m_pendingDeletions == 0 && !m_pendingPurgeSignal) {
+        QTestEventLoop::instance().exitLoop();
+    }
+}
+
+void TodoPurgerTest::onTodosPurged(bool success, int numDeleted, int numIgnored)
+{
+    QVERIFY(success);
+    m_pendingPurgeSignal = false;
+    m_numDeleted = numDeleted;
+    m_numIgnored = numIgnored;
+
+    if (m_pendingDeletions == 0) {
+        QTestEventLoop::instance().enterLoop(10);
+        QVERIFY(!QTestEventLoop::instance().timeout());
+    }
+}
+
+void TodoPurgerTest::createTree()
+{
+    createTodo(tr("a"), QString(), true);  // Will be deleted
+    createTodo(tr("b"), QString(), false); // Won't be deleted
+
+    // Completed tree
+    createTodo(tr("c"), QString(), true);   // Will be deleted
+    createTodo(tr("c1"), tr("c"), true);    // Will be deleted
+    createTodo(tr("c1.1"), tr("c1"), true); // Will be deleted
+    createTodo(tr("c1.2"), tr("c1"), true); // Will be deleted
+
+    // Root completed but children not completed
+    createTodo(tr("d"), QString(), true);    // Will be ignored (uncomplete \
children) +    createTodo(tr("d1"), tr("d"), false);    // Won't be deleted
+    createTodo(tr("d1.1"), tr("d1"), false); // Won't be deleted
+    createTodo(tr("d1.2"), tr("d1"), false); // Won't be deleted
+
+    // Root uncomplete with children complete
+    createTodo(tr("e"), QString(), false);    // Won't be deleted
+    createTodo(tr("e1"), tr("e"), true);      // Will be deleted
+    createTodo(tr("e1.1"), tr("e1"), true);   // Will be deleted
+    createTodo(tr("e1.2"), tr("e1"), true);   // Will be deleted
+
+    // Recurring uncomplete
+    createTodo(tr("f"), QString(), false, true); // Won't be deleted
+
+    // Recurring complete, this one is not deleted because recurrence didn't end
+    createTodo(tr("g"), QString(), true, true); // Won't be deleted
+
+    createTodo(tr("h"), QString(), true);    // Will be ignored (uncomplete \
children) +    createTodo(tr("h1"), tr("h"), false);    // Won't be deleted
+    createTodo(tr("h1.1"), tr("h1"), true);  // Will be deleted
+    createTodo(tr("h1.2"), tr("h1"), true);  // Will be deleted
+
+
+    // Now wait for incidences do be created
+    QTestEventLoop::instance().enterLoop(10);
+    QVERIFY(!QTestEventLoop::instance().timeout());
+}
+
+QTEST_AKONADIMAIN(TodoPurgerTest, GUI)
diff --git a/akonadi/calendar/tests/todopurgertest.h \
b/akonadi/calendar/tests/todopurgertest.h new file mode 100644
index 0000000..7cb5839
--- /dev/null
+++ b/akonadi/calendar/tests/todopurgertest.h
@@ -0,0 +1,65 @@
+/*
+    Copyright (c) 2013 Sérgio Martins <iamsergio@gmail.com>
+
+    This library is free software; you can redistribute it and/or modify it
+    under the terms of the GNU Library General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    This library is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
+    License for more details.
+
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to the
+    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301, USA.
+*/
+
+#ifndef TODOPURGER_TEST_H_
+#define TODOPURGER_TEST_H_
+
+#include <kcalcore/calendar.h>
+#include <akonadi/collection.h>
+#include <QObject>
+#include <QString>
+
+namespace Akonadi {
+    class ETMCalendar;
+    class TodoPurger;
+}
+
+class TodoPurgerTest : public QObject, KCalCore::Calendar::CalendarObserver
+{
+    Q_OBJECT
+private Q_SLOTS:
+    void initTestCase();
+    void cleanupTestCase();
+    void testPurge();
+
+public:
+    void calendarIncidenceAdded( const KCalCore::Incidence::Ptr &incidence );   \
/**Q_DECL_OVERRIDE*/ +    void calendarIncidenceDeleted( const \
KCalCore::Incidence::Ptr &incidence ); /**Q_DECL_OVERRIDE*/ +
+public Q_SLOTS:
+    void onTodosPurged(bool success, int numDeleted, int numIgnored);
+
+private:
+    void createTree();
+    void createTodo(const QString &uid, const QString &parentUid, bool completed, \
bool recurring = false); +    void fetchCollection();
+
+    Akonadi::ETMCalendar *m_calendar;
+    Akonadi::Collection m_collection;
+    int m_pendingCreations;
+    int m_pendingDeletions;
+    bool m_pendingPurgeSignal;
+
+    int m_numDeleted;
+    int m_numIgnored;
+
+    Akonadi::TodoPurger *m_todoPurger;
+};
+
+#endif
diff --git a/akonadi/calendar/tests/unittestbase.cpp \
b/akonadi/calendar/tests/unittestbase.cpp new file mode 100644
index 0000000..9e7b868
--- /dev/null
+++ b/akonadi/calendar/tests/unittestbase.cpp
@@ -0,0 +1,198 @@
+/*
+    Copyright (c) 2013 Sérgio Martins <iamsergio@gmail.com>
+
+    This library is free software; you can redistribute it and/or modify it
+    under the terms of the GNU Library General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    This library is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
+    License for more details.
+
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to the
+    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301, USA.
+*/
+
+
+#include "unittestbase.h"
+#include "helper.h"
+#include "../fetchjobcalendar.h"
+#include "mailclient_p.h"
+
+#include <kcalcore/event.h>
+#include <kcalcore/icalformat.h>
+#include <akonadi/item.h>
+#include <akonadi/itemcreatejob.h>
+#include <akonadi/calendar/incidencechanger.h>
+#include <akonadi/calendar/itiphandler.h>
+
+#include <QString>
+#include <QFile>
+#include <QByteArray>
+#include <QTestEventLoop>
+#include <qtest.h>
+
+using namespace Akonadi;
+using namespace KCalCore;
+
+UnitTestBase::UnitTestBase()
+{
+    qRegisterMetaType<Akonadi::Item>("Akonadi::Item");
+    qRegisterMetaType<QList<Akonadi::IncidenceChanger::ChangeType> \
>("QList<Akonadi::IncidenceChanger::ChangeType>"); +    \
> qRegisterMetaType<QVector<Akonadi::Item::Id> >("QVector<Akonadi::Item::Id>");
+    qRegisterMetaType<Akonadi::MailClient::Result>("Akonadi::MailClient::Result");
+
+    mChanger = new IncidenceChanger(this);
+    mChanger->setShowDialogsOnError(false);
+    mChanger->setHistoryEnabled(true);
+
+    mCollection = Helper::fetchCollection();
+    Q_ASSERT(mCollection.isValid());
+    mChanger->setDefaultCollection(mCollection);
+}
+
+void UnitTestBase::waitForIt()
+{
+    QTestEventLoop::instance().enterLoop(10);
+    QVERIFY(!QTestEventLoop::instance().timeout());
+}
+
+void UnitTestBase::stopWaiting()
+{
+    QTestEventLoop::instance().exitLoop();
+}
+
+void UnitTestBase::createIncidence(const QString &uid)
+{
+    Item item = generateIncidence(uid);
+    createIncidence(item);
+}
+
+void UnitTestBase::createIncidence(const Item &item)
+{
+    QVERIFY(mCollection.isValid());
+    ItemCreateJob *job = new ItemCreateJob(item, mCollection, this);
+    QVERIFY(job->exec());
+}
+
+void UnitTestBase::verifyExists(const QString &uid, bool exists)
+{
+    FetchJobCalendar *calendar = new FetchJobCalendar();
+    connect(calendar, SIGNAL(loadFinished(bool,QString)), \
SLOT(onLoadFinished(bool,QString))); +    waitForIt();
+    calendar->deleteLater();
+
+    QCOMPARE(calendar->incidence(uid) != 0, exists);
+}
+
+Akonadi::Item::List UnitTestBase::calendarItems()
+{
+    FetchJobCalendar::Ptr calendar = FetchJobCalendar::Ptr(new FetchJobCalendar());
+    connect(calendar.data(), SIGNAL(loadFinished(bool,QString)), \
SLOT(onLoadFinished(bool,QString))); +    waitForIt();
+    KCalCore::ICalFormat format;
+    QString dump = format.toString(calendar.staticCast<KCalCore::Calendar>());
+    qDebug() << dump;
+    calendar->deleteLater();
+    return calendar->items();
+}
+
+void UnitTestBase::onLoadFinished(bool success, const QString &)
+{
+    QVERIFY(success);
+    stopWaiting();
+}
+
+void UnitTestBase::compareCalendars(const KCalCore::Calendar::Ptr &expectedCalendar)
+{
+    FetchJobCalendar::Ptr calendar = FetchJobCalendar::Ptr(new FetchJobCalendar());
+    connect(calendar.data(), SIGNAL(loadFinished(bool,QString)), \
SLOT(onLoadFinished(bool,QString))); +    waitForIt();
+
+
+    // Now compare the expected calendar to the calendar we got.
+    Incidence::List incidences = calendar->incidences();
+    Incidence::List expectedIncidences = expectedCalendar->incidences();
+
+    // First, replace the randomly generated UIDs with the UID that came in the \
invitation e-mail... +    foreach (const KCalCore::Incidence::Ptr &incidence, \
incidences) { +        incidence->setUid(incidence->schedulingID());
+        qDebug() << "We have incidece with uid=" << incidence->uid()
+                 << "; instanceidentifier=" << incidence->instanceIdentifier();
+        foreach (const KCalCore::Attendee::Ptr &attendee, incidence->attendees()) {
+            attendee->setUid(attendee->email());
+        }
+    }
+
+    // ... so we can compare them
+    foreach (const KCalCore::Incidence::Ptr &incidence, expectedIncidences) {
+        incidence->setUid(incidence->schedulingID());
+        qDebug() << "We expect incidece with uid=" << incidence->uid()
+                 << "; instanceidentifier=" << incidence->instanceIdentifier();
+        foreach (const KCalCore::Attendee::Ptr &attendee, incidence->attendees()) {
+            attendee->setUid(attendee->email());
+        }
+    }
+
+    QCOMPARE(incidences.count(), expectedIncidences.count());
+
+    foreach (const KCalCore::Incidence::Ptr &expectedIncidence, expectedIncidences) \
{ +        KCalCore::Incidence::Ptr incidence;
+        for (int i=0; i<incidences.count(); i++) {
+            if (incidences.at(i)->instanceIdentifier() == \
expectedIncidence->instanceIdentifier()) { +                incidence = \
incidences.at(i); +                incidences.remove(i);
+                break;
+            }
+        }
+        QVERIFY(incidence);
+        // Don't fail on creation times, which are obviously different
+        expectedIncidence->setCreated(incidence->created());
+
+        if (*expectedIncidence != *incidence) {
+            ICalFormat format;
+            QString expectedData = format.toString(expectedIncidence);
+            QString gotData = format.toString(incidence);
+            qDebug() << "Test failed, expected:\n" << expectedData << "\nbut got " \
<< gotData; +            QVERIFY(false);
+        }
+    }
+}
+
+/** static */
+QByteArray UnitTestBase::readFile(const QString &filename)
+{
+    QFile file(filename);
+    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+        return QByteArray();
+    }
+
+    return file.readAll();
+}
+
+Item UnitTestBase::generateIncidence(const QString &uid, const QString &organizer)
+{
+    Item item;
+    item.setMimeType(KCalCore::Event::eventMimeType());
+    KCalCore::Incidence::Ptr incidence = KCalCore::Incidence::Ptr(new \
KCalCore::Event()); +
+    if (!uid.isEmpty()) {
+        incidence->setUid(uid);
+    }
+
+    const KDateTime now = KDateTime::currentUtcDateTime();
+    incidence->setDtStart(now);
+    incidence->setDateTime(now.addSecs(3600), Incidence::RoleEnd);
+    incidence->setSummary(QLatin1String("summary"));
+    item.setPayload<KCalCore::Incidence::Ptr>(incidence);
+
+    if (!organizer.isEmpty()) {
+        incidence->setOrganizer(organizer);
+    }
+
+    return item;
+}
diff --git a/akonadi/calendar/tests/unittestbase.h \
b/akonadi/calendar/tests/unittestbase.h new file mode 100644
index 0000000..14dec78
--- /dev/null
+++ b/akonadi/calendar/tests/unittestbase.h
@@ -0,0 +1,60 @@
+/*
+    Copyright (c) 2013 Sérgio Martins <iamsergio@gmail.com>
+
+    This library is free software; you can redistribute it and/or modify it
+    under the terms of the GNU Library General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    This library is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
+    License for more details.
+
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to the
+    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301, USA.
+*/
+
+
+#ifndef UNITTEST_BASE_H
+#define UNITTEST_BASE_H
+
+#include <kcalcore/calendar.h>
+#include <akonadi/collection.h>
+#include <akonadi/item.h>
+
+#include <QObject>
+#include <QString>
+
+namespace Akonadi {
+    class IncidenceChanger;
+}
+
+class UnitTestBase : public QObject {
+    Q_OBJECT
+public:
+    UnitTestBase();
+    void waitForIt(); // Waits 10 seconds for signals
+    void stopWaiting();
+    void createIncidence(const QString &uid);
+    void createIncidence(const Akonadi::Item &item);
+
+    void verifyExists(const QString &uid, bool exists);
+    Akonadi::Item::List calendarItems();
+
+public Q_SLOTS:
+    void onLoadFinished(bool success, const QString &errorMessage);
+
+protected:
+
+    void compareCalendars(const KCalCore::Calendar::Ptr &expectedCalendar);
+    static QByteArray readFile(const QString &filename);
+    static Akonadi::Item generateIncidence(const QString &uid, const QString \
&organizer = QString()); +
+    Akonadi::Collection mCollection;
+    Akonadi::IncidenceChanger *mChanger;
+};
+
+#endif
diff --git a/akonadi/calendar/tests/unittestenv/config-sqlite-db.xml \
b/akonadi/calendar/tests/unittestenv/config-sqlite-db.xml index 6e8388f..1ba6b3f \
                100644
--- a/akonadi/calendar/tests/unittestenv/config-sqlite-db.xml
+++ b/akonadi/calendar/tests/unittestenv/config-sqlite-db.xml
@@ -3,8 +3,6 @@
   <confighome>xdgconfig-sqlite.db</confighome>
   <datahome>xdglocal</datahome>
   <agent synchronize="true">akonadi_ical_resource</agent>
-  <agent synchronize="true">akonadi_maildir_resource</agent>
-  <agent synchronize="true">akonadi_mailtransport_dummy_resource</agent>
   <envvar name="AKONADI_DISABLE_AGENT_AUTOSTART">true</envvar>
   <envvar name="TESTRUNNER_DB_ENVIRONMENT">sqlite</envvar>
 </config>
diff --git a/akonadi/calendar/tests/unittestenv/kdehome/share/config/akonadi_maildir_resource_0rc \
b/akonadi/calendar/tests/unittestenv/kdehome/share/config/akonadi_maildir_resource_0rc
 deleted file mode 100644
index 2488d2d..0000000
--- a/akonadi/calendar/tests/unittestenv/kdehome/share/config/akonadi_maildir_resource_0rc
                
+++ /dev/null
@@ -1,2 +0,0 @@
-[General]
-Path[$e]=$HOME/.local/share/local-mail
diff --git a/akonadi/calendar/tests/unittestenv/kdehome/share/config/akonadi_mailtransport_dummy_resource_0rc \
b/akonadi/calendar/tests/unittestenv/kdehome/share/config/akonadi_mailtransport_dummy_resource_0rc
 deleted file mode 100644
index eddc6c7..0000000
--- a/akonadi/calendar/tests/unittestenv/kdehome/share/config/akonadi_mailtransport_dummy_resource_0rc
                
+++ /dev/null
@@ -1,2 +0,0 @@
-[General]
-Sink=4
diff --git a/akonadi/calendar/tests/unittestenv/kdehome/share/config/kdebugrc \
b/akonadi/calendar/tests/unittestenv/kdehome/share/config/kdebugrc new file mode \
100644 index 0000000..848ed66
--- /dev/null
+++ b/akonadi/calendar/tests/unittestenv/kdehome/share/config/kdebugrc
@@ -0,0 +1,1672 @@
+DisableAll=false
+
+[1000]
+InfoOutput=2
+
+[10000]
+InfoOutput=2
+
+[100000]
+InfoOutput=2
+
+[100001]
+InfoOutput=2
+
+[100100]
+InfoOutput=2
+
+[100101]
+InfoOutput=2
+
+[100200]
+InfoOutput=2
+
+[10500]
+InfoOutput=2
+
+[1100]
+InfoOutput=2
+
+[11000]
+InfoOutput=2
+
+[11002]
+InfoOutput=2
+
+[11003]
+InfoOutput=2
+
+[11004]
+InfoOutput=2
+
+[11005]
+InfoOutput=2
+
+[12000]
+InfoOutput=2
+
+[12001]
+InfoOutput=2
+
+[12002]
+InfoOutput=2
+
+[12003]
+InfoOutput=2
+
+[12004]
+InfoOutput=2
+
+[12005]
+InfoOutput=2
+
+[12006]
+InfoOutput=2
+
+[12007]
+InfoOutput=2
+
+[12008]
+InfoOutput=2
+
+[12009]
+InfoOutput=2
+
+[1201]
+InfoOutput=2
+
+[12010]
+InfoOutput=2
+
+[12011]
+InfoOutput=2
+
+[12012]
+InfoOutput=2
+
+[1203]
+InfoOutput=2
+
+[1204]
+InfoOutput=2
+
+[1205]
+InfoOutput=2
+
+[1206]
+InfoOutput=2
+
+[1207]
+InfoOutput=2
+
+[1208]
+InfoOutput=2
+
+[1209]
+InfoOutput=2
+
+[1211]
+InfoOutput=2
+
+[1212]
+InfoOutput=2
+
+[1215]
+InfoOutput=2
+
+[1216]
+InfoOutput=2
+
+[1218]
+InfoOutput=2
+
+[1220]
+InfoOutput=2
+
+[1221]
+InfoOutput=2
+
+[1222]
+InfoOutput=2
+
+[13000]
+InfoOutput=2
+
+[13001]
+InfoOutput=2
+
+[13002]
+InfoOutput=2
+
+[13010]
+InfoOutput=2
+
+[13020]
+InfoOutput=2
+
+[13025]
+InfoOutput=2
+
+[13030]
+InfoOutput=2
+
+[13033]
+InfoOutput=2
+
+[13035]
+InfoOutput=2
+
+[13040]
+InfoOutput=2
+
+[13050]
+InfoOutput=2
+
+[13051]
+InfoOutput=2
+
+[13060]
+InfoOutput=2
+
+[13070]
+InfoOutput=2
+
+[1400]
+InfoOutput=2
+
+[14000]
+InfoOutput=2
+
+[14001]
+InfoOutput=2
+
+[1401]
+InfoOutput=2
+
+[14010]
+InfoOutput=2
+
+[1402]
+InfoOutput=2
+
+[1410]
+InfoOutput=2
+
+[14100]
+InfoOutput=2
+
+[14101]
+InfoOutput=2
+
+[14110]
+InfoOutput=2
+
+[14111]
+InfoOutput=2
+
+[14120]
+InfoOutput=2
+
+[14121]
+InfoOutput=2
+
+[14130]
+InfoOutput=2
+
+[14131]
+InfoOutput=2
+
+[14140]
+InfoOutput=2
+
+[14141]
+InfoOutput=2
+
+[14150]
+InfoOutput=2
+
+[14151]
+InfoOutput=2
+
+[14152]
+InfoOutput=2
+
+[14153]
+InfoOutput=2
+
+[14160]
+InfoOutput=2
+
+[14161]
+InfoOutput=2
+
+[14170]
+InfoOutput=2
+
+[14171]
+InfoOutput=2
+
+[14180]
+InfoOutput=2
+
+[14181]
+InfoOutput=2
+
+[14190]
+InfoOutput=2
+
+[14191]
+InfoOutput=2
+
+[14192]
+InfoOutput=2
+
+[1420]
+InfoOutput=2
+
+[14200]
+InfoOutput=2
+
+[1421]
+InfoOutput=2
+
+[14210]
+InfoOutput=2
+
+[14220]
+InfoOutput=2
+
+[1430]
+InfoOutput=2
+
+[14300]
+InfoOutput=2
+
+[14301]
+InfoOutput=2
+
+[14302]
+InfoOutput=2
+
+[14303]
+InfoOutput=2
+
+[14304]
+InfoOutput=2
+
+[14305]
+InfoOutput=2
+
+[14306]
+InfoOutput=2
+
+[14307]
+InfoOutput=2
+
+[14308]
+InfoOutput=2
+
+[14309]
+InfoOutput=2
+
+[1431]
+InfoOutput=2
+
+[14310]
+InfoOutput=2
+
+[14311]
+InfoOutput=2
+
+[14312]
+InfoOutput=2
+
+[14313]
+InfoOutput=2
+
+[14314]
+InfoOutput=2
+
+[14315]
+InfoOutput=2
+
+[14316]
+InfoOutput=2
+
+[14317]
+InfoOutput=2
+
+[14318]
+InfoOutput=2
+
+[1432]
+InfoOutput=2
+
+[1433]
+InfoOutput=2
+
+[1440]
+InfoOutput=2
+
+[14400]
+InfoOutput=2
+
+[1441]
+InfoOutput=2
+
+[15000]
+InfoOutput=2
+
+[1511]
+InfoOutput=2
+
+[1512]
+InfoOutput=2
+
+[1601]
+InfoOutput=2
+
+[161]
+InfoOutput=2
+
+[170]
+InfoOutput=2
+
+[174]
+InfoOutput=2
+
+[175]
+InfoOutput=2
+
+[176]
+InfoOutput=2
+
+[179]
+InfoOutput=2
+
+[180]
+InfoOutput=2
+
+[1800]
+InfoOutput=2
+
+[1801]
+InfoOutput=2
+
+[1802]
+InfoOutput=2
+
+[1803]
+InfoOutput=2
+
+[1804]
+InfoOutput=2
+
+[1805]
+InfoOutput=2
+
+[1806]
+InfoOutput=2
+
+[1901]
+InfoOutput=2
+
+[1902]
+InfoOutput=2
+
+[1903]
+InfoOutput=2
+
+[2000]
+InfoOutput=2
+
+[20000]
+InfoOutput=2
+
+[200000]
+InfoOutput=2
+
+[200001]
+InfoOutput=2
+
+[200002]
+InfoOutput=2
+
+[200003]
+InfoOutput=2
+
+[200004]
+InfoOutput=2
+
+[20001]
+InfoOutput=2
+
+[2001]
+InfoOutput=2
+
+[20010]
+InfoOutput=2
+
+[20011]
+InfoOutput=2
+
+[20012]
+InfoOutput=2
+
+[2002]
+InfoOutput=2
+
+[2003]
+InfoOutput=2
+
+[2100]
+InfoOutput=2
+
+[2200]
+InfoOutput=2
+
+[23000]
+InfoOutput=2
+
+[23100]
+InfoOutput=2
+
+[240]
+InfoOutput=2
+
+[2400]
+InfoOutput=2
+
+[24000]
+InfoOutput=2
+
+[24001]
+InfoOutput=2
+
+[24002]
+InfoOutput=2
+
+[2401]
+InfoOutput=2
+
+[2402]
+InfoOutput=2
+
+[2403]
+InfoOutput=2
+
+[2404]
+InfoOutput=2
+
+[2405]
+InfoOutput=2
+
+[260]
+InfoOutput=2
+
+[265]
+InfoOutput=2
+
+[26500]
+InfoOutput=2
+
+[26550]
+InfoOutput=2
+
+[26560]
+InfoOutput=2
+
+[26600]
+InfoOutput=2
+
+[26650]
+InfoOutput=2
+
+[28000]
+InfoOutput=2
+
+[281]
+InfoOutput=2
+
+[282]
+InfoOutput=2
+
+[283]
+InfoOutput=2
+
+[285]
+InfoOutput=2
+
+[29000]
+InfoOutput=2
+
+[291]
+InfoOutput=2
+
+[292]
+InfoOutput=2
+
+[293]
+InfoOutput=2
+
+[297]
+InfoOutput=2
+
+[299]
+InfoOutput=2
+
+[3000]
+InfoOutput=2
+
+[300000]
+InfoOutput=2
+
+[300001]
+InfoOutput=2
+
+[300100]
+InfoOutput=2
+
+[300101]
+InfoOutput=2
+
+[300102]
+InfoOutput=2
+
+[300103]
+InfoOutput=2
+
+[300104]
+InfoOutput=2
+
+[300105]
+InfoOutput=2
+
+[300106]
+InfoOutput=2
+
+[300200]
+InfoOutput=2
+
+[30501]
+InfoOutput=2
+
+[30502]
+InfoOutput=2
+
+[30503]
+InfoOutput=2
+
+[30504]
+InfoOutput=2
+
+[30505]
+InfoOutput=2
+
+[30506]
+InfoOutput=2
+
+[30507]
+InfoOutput=2
+
+[30508]
+InfoOutput=2
+
+[30509]
+InfoOutput=2
+
+[30510]
+InfoOutput=2
+
+[30511]
+InfoOutput=2
+
+[30512]
+InfoOutput=2
+
+[30513]
+InfoOutput=2
+
+[30514]
+InfoOutput=2
+
+[30515]
+InfoOutput=2
+
+[30516]
+InfoOutput=2
+
+[30517]
+InfoOutput=2
+
+[30518]
+InfoOutput=2
+
+[30519]
+InfoOutput=2
+
+[30520]
+InfoOutput=2
+
+[30521]
+InfoOutput=2
+
+[30522]
+InfoOutput=2
+
+[30523]
+InfoOutput=2
+
+[30525]
+InfoOutput=2
+
+[3100]
+InfoOutput=2
+
+[32500]
+InfoOutput=2
+
+[32600]
+InfoOutput=2
+
+[34001]
+InfoOutput=2
+
+[35000]
+InfoOutput=2
+
+[38000]
+InfoOutput=2
+
+[399]
+InfoOutput=2
+
+[410]
+InfoOutput=2
+
+[4300]
+InfoOutput=2
+
+[4400]
+InfoOutput=2
+
+[44000]
+InfoOutput=2
+
+[44001]
+InfoOutput=2
+
+[44010]
+InfoOutput=2
+
+[44019]
+InfoOutput=2
+
+[44020]
+InfoOutput=2
+
+[44021]
+InfoOutput=2
+
+[44022]
+InfoOutput=2
+
+[44023]
+InfoOutput=2
+
+[44024]
+InfoOutput=2
+
+[4500]
+InfoOutput=2
+
+[4600]
+InfoOutput=2
+
+[4610]
+InfoOutput=2
+
+[4620]
+InfoOutput=2
+
+[4630]
+InfoOutput=2
+
+[4640]
+InfoOutput=2
+
+[4700]
+InfoOutput=2
+
+[4710]
+InfoOutput=2
+
+[4711]
+InfoOutput=2
+
+[4712]
+InfoOutput=2
+
+[4713]
+InfoOutput=2
+
+[4714]
+InfoOutput=2
+
+[4715]
+InfoOutput=2
+
+[500]
+InfoOutput=2
+
+[50001]
+InfoOutput=2
+
+[50003]
+InfoOutput=2
+
+[50004]
+InfoOutput=2
+
+[50005]
+InfoOutput=2
+
+[50006]
+InfoOutput=2
+
+[50007]
+InfoOutput=2
+
+[5001]
+InfoOutput=2
+
+[5002]
+InfoOutput=2
+
+[5003]
+InfoOutput=2
+
+[5005]
+InfoOutput=2
+
+[5007]
+InfoOutput=2
+
+[5009]
+InfoOutput=2
+
+[5010]
+InfoOutput=2
+
+[5011]
+InfoOutput=2
+
+[5012]
+InfoOutput=2
+
+[5050]
+InfoOutput=2
+
+[5051]
+InfoOutput=2
+
+[5052]
+InfoOutput=2
+
+[5100]
+InfoOutput=2
+
+[51000]
+InfoOutput=2
+
+[51001]
+InfoOutput=2
+
+[51002]
+InfoOutput=2
+
+[51003]
+InfoOutput=2
+
+[51004]
+InfoOutput=2
+
+[51005]
+InfoOutput=2
+
+[51006]
+InfoOutput=2
+
+[51007]
+InfoOutput=2
+
+[51010]
+InfoOutput=2
+
+[51011]
+InfoOutput=2
+
+[51012]
+InfoOutput=2
+
+[51013]
+InfoOutput=2
+
+[51014]
+InfoOutput=2
+
+[51020]
+InfoOutput=2
+
+[5149]
+InfoOutput=2
+
+[5150]
+InfoOutput=2
+
+[5151]
+InfoOutput=2
+
+[5152]
+InfoOutput=2
+
+[5153]
+InfoOutput=2
+
+[5154]
+InfoOutput=2
+
+[5200]
+InfoOutput=2
+
+[5250]
+InfoOutput=2
+
+[5251]
+InfoOutput=2
+
+[5252]
+InfoOutput=2
+
+[5253]
+InfoOutput=2
+
+[5254]
+InfoOutput=2
+
+[5255]
+InfoOutput=2
+
+[5256]
+InfoOutput=2
+
+[5257]
+InfoOutput=2
+
+[5258]
+InfoOutput=2
+
+[5259]
+InfoOutput=2
+
+[5260]
+InfoOutput=2
+
+[5261]
+InfoOutput=2
+
+[5262]
+InfoOutput=2
+
+[5263]
+InfoOutput=2
+
+[5264]
+InfoOutput=2
+
+[5265]
+InfoOutput=2
+
+[5266]
+InfoOutput=2
+
+[5295]
+InfoOutput=2
+
+[5300]
+InfoOutput=2
+
+[5310]
+InfoOutput=2
+
+[5320]
+InfoOutput=2
+
+[5321]
+InfoOutput=2
+
+[5322]
+InfoOutput=2
+
+[5323]
+InfoOutput=2
+
+[5324]
+InfoOutput=2
+
+[5325]
+InfoOutput=2
+
+[5326]
+InfoOutput=2
+
+[5327]
+InfoOutput=2
+
+[5328]
+InfoOutput=2
+
+[5329]
+InfoOutput=2
+
+[5350]
+InfoOutput=2
+
+[550]
+InfoOutput=2
+
+[5500]
+InfoOutput=2
+
+[551]
+InfoOutput=2
+
+[5510]
+InfoOutput=2
+
+[5511]
+InfoOutput=2
+
+[5512]
+InfoOutput=2
+
+[5600]
+InfoOutput=2
+
+[5601]
+InfoOutput=2
+
+[5602]
+InfoOutput=2
+
+[5650]
+InfoOutput=2
+
+[5700]
+InfoOutput=2
+
+[5720]
+InfoOutput=2
+
+[5800]
+InfoOutput=2
+
+[5810]
+InfoOutput=2
+
+[5820]
+InfoOutput=2
+
+[5850]
+InfoOutput=2
+
+[5860]
+InfoOutput=2
+
+[5890]
+InfoOutput=2
+
+[5900]
+InfoOutput=2
+
+[5950]
+InfoOutput=2
+
+[5951]
+InfoOutput=2
+
+[5952]
+InfoOutput=2
+
+[5953]
+InfoOutput=2
+
+[5954]
+InfoOutput=2
+
+[5955]
+InfoOutput=2
+
+[5960]
+InfoOutput=2
+
+[5970]
+InfoOutput=2
+
+[5975]
+InfoOutput=2
+
+[600]
+InfoOutput=2
+
+[6000]
+InfoOutput=2
+
+[60001]
+InfoOutput=2
+
+[60002]
+InfoOutput=2
+
+[60005]
+InfoOutput=2
+
+[60010]
+InfoOutput=2
+
+[6005]
+InfoOutput=2
+
+[601]
+InfoOutput=2
+
+[6010]
+InfoOutput=2
+
+[6011]
+InfoOutput=2
+
+[6020]
+InfoOutput=2
+
+[6030]
+InfoOutput=2
+
+[6031]
+InfoOutput=2
+
+[6035]
+InfoOutput=2
+
+[6036]
+InfoOutput=2
+
+[6040]
+InfoOutput=2
+
+[6041]
+InfoOutput=2
+
+[6045]
+InfoOutput=2
+
+[6050]
+InfoOutput=2
+
+[6060]
+InfoOutput=2
+
+[6061]
+InfoOutput=2
+
+[6070]
+InfoOutput=2
+
+[6080]
+InfoOutput=2
+
+[6090]
+InfoOutput=2
+
+[6100]
+InfoOutput=2
+
+[6200]
+InfoOutput=2
+
+[6201]
+InfoOutput=2
+
+[6210]
+InfoOutput=2
+
+[65432]
+InfoOutput=2
+
+[66666]
+InfoOutput=2
+
+[67000]
+InfoOutput=2
+
+[67100]
+InfoOutput=2
+
+[67200]
+InfoOutput=2
+
+[700]
+InfoOutput=2
+
+[7000]
+InfoOutput=2
+
+[7002]
+InfoOutput=2
+
+[7003]
+InfoOutput=2
+
+[7004]
+InfoOutput=2
+
+[7005]
+InfoOutput=2
+
+[7006]
+InfoOutput=2
+
+[7007]
+InfoOutput=2
+
+[7008]
+InfoOutput=2
+
+[701]
+InfoOutput=2
+
+[7011]
+InfoOutput=2
+
+[7014]
+InfoOutput=2
+
+[7015]
+InfoOutput=2
+
+[7016]
+InfoOutput=2
+
+[7017]
+InfoOutput=2
+
+[7019]
+InfoOutput=2
+
+[702]
+InfoOutput=2
+
+[7020]
+InfoOutput=2
+
+[7021]
+InfoOutput=2
+
+[7022]
+InfoOutput=2
+
+[7023]
+InfoOutput=2
+
+[7024]
+InfoOutput=2
+
+[7025]
+InfoOutput=2
+
+[7027]
+InfoOutput=2
+
+[7028]
+InfoOutput=2
+
+[7029]
+InfoOutput=2
+
+[7030]
+InfoOutput=2
+
+[7031]
+InfoOutput=2
+
+[7032]
+InfoOutput=2
+
+[7033]
+InfoOutput=2
+
+[7034]
+InfoOutput=2
+
+[704]
+InfoOutput=2
+
+[7040]
+InfoOutput=2
+
+[7041]
+InfoOutput=2
+
+[7042]
+InfoOutput=2
+
+[7043]
+InfoOutput=2
+
+[7044]
+InfoOutput=2
+
+[710]
+InfoOutput=2
+
+[7101]
+InfoOutput=2
+
+[7102]
+InfoOutput=2
+
+[7103]
+InfoOutput=2
+
+[7104]
+InfoOutput=2
+
+[7105]
+InfoOutput=2
+
+[7106]
+InfoOutput=2
+
+[7107]
+InfoOutput=2
+
+[7108]
+InfoOutput=2
+
+[7109]
+InfoOutput=2
+
+[711]
+InfoOutput=2
+
+[7110]
+InfoOutput=2
+
+[7111]
+InfoOutput=2
+
+[7112]
+InfoOutput=2
+
+[7115]
+InfoOutput=2
+
+[7116]
+InfoOutput=2
+
+[7117]
+InfoOutput=2
+
+[7119]
+InfoOutput=2
+
+[712]
+InfoOutput=2
+
+[7120]
+InfoOutput=2
+
+[7121]
+InfoOutput=2
+
+[7122]
+InfoOutput=2
+
+[7123]
+InfoOutput=2
+
+[7124]
+InfoOutput=2
+
+[7125]
+InfoOutput=2
+
+[7126]
+InfoOutput=2
+
+[7127]
+InfoOutput=2
+
+[7128]
+InfoOutput=2
+
+[7129]
+InfoOutput=2
+
+[713]
+InfoOutput=2
+
+[7131]
+InfoOutput=2
+
+[800]
+InfoOutput=2
+
+[80001]
+InfoOutput=2
+
+[8050]
+InfoOutput=2
+
+[8051]
+InfoOutput=2
+
+[8060]
+InfoOutput=2
+
+[8100]
+InfoOutput=2
+
+[8101]
+InfoOutput=2
+
+[8102]
+InfoOutput=2
+
+[8103]
+InfoOutput=2
+
+[8104]
+InfoOutput=2
+
+[8105]
+InfoOutput=2
+
+[8106]
+InfoOutput=2
+
+[8110]
+InfoOutput=2
+
+[8111]
+InfoOutput=2
+
+[8112]
+InfoOutput=2
+
+[8113]
+InfoOutput=2
+
+[9000]
+InfoOutput=2
+
+[90000]
+InfoOutput=2
+
+[9001]
+InfoOutput=2
+
+[90010]
+InfoOutput=2
+
+[9002]
+InfoOutput=2
+
+[90020]
+InfoOutput=2
+
+[9003]
+InfoOutput=2
+
+[9004]
+InfoOutput=2
+
+[9007]
+InfoOutput=2
+
+[9010]
+InfoOutput=2
+
+[90100]
+InfoOutput=2
+
+[9011]
+InfoOutput=2
+
+[90110]
+InfoOutput=2
+
+[9012]
+InfoOutput=2
+
+[90120]
+InfoOutput=2
+
+[9013]
+InfoOutput=2
+
+[90130]
+InfoOutput=2
+
+[90150]
+InfoOutput=2
+
+[90160]
+InfoOutput=2
+
+[9017]
+InfoOutput=2
+
+[90170]
+InfoOutput=2
+
+[90180]
+InfoOutput=2
+
+[90190]
+InfoOutput=2
+
+[90210]
+InfoOutput=2
+
+[9024]
+InfoOutput=2
+
+[9025]
+InfoOutput=2
+
+[9032]
+InfoOutput=2
+
+[9035]
+InfoOutput=2
+
+[9037]
+InfoOutput=2
+
+[9038]
+InfoOutput=2
+
+[9039]
+InfoOutput=2
+
+[9040]
+InfoOutput=2
+
+[9041]
+InfoOutput=2
+
+[9042]
+InfoOutput=2
+
+[9043]
+InfoOutput=2
+
+[9044]
+InfoOutput=2
+
+[9045]
+InfoOutput=2
+
+[9046]
+InfoOutput=2
+
+[912]
+InfoOutput=2
+
+[920]
+InfoOutput=2
+
+[921]
+InfoOutput=2
+
+[930]
+InfoOutput=2
+
+[9500]
+InfoOutput=2
+
+[9501]
+InfoOutput=2
+
+[9502]
+InfoOutput=2
+
+[9503]
+InfoOutput=2
+
+[9504]
+InfoOutput=2
+
+[9505]
+InfoOutput=2
+
+[9506]
+InfoOutput=2
+
+[9507]
+InfoOutput=2
+
+[9508]
+InfoOutput=2
+
+[9509]
+InfoOutput=2
+
+[9510]
+InfoOutput=2
+
+[9511]
+InfoOutput=2
+
+[9512]
+InfoOutput=2
+
+[9513]
+InfoOutput=2
+
+[9514]
+InfoOutput=2
+
+[9515]
+InfoOutput=2
+
+[9516]
+InfoOutput=2
+
+[9517]
+InfoOutput=2
+
+[9518]
+InfoOutput=2
+
+[9519]
+InfoOutput=2
+
+[9520]
+InfoOutput=2
+
+[9521]
+InfoOutput=2
+
+[9522]
+InfoOutput=2
+
+[9523]
+InfoOutput=2
+
+[9524]
+InfoOutput=2
+
+[9525]
+InfoOutput=2
+
+[9526]
+InfoOutput=2
+
+[9527]
+InfoOutput=2
+
+[9528]
+InfoOutput=2
+
+[9529]
+InfoOutput=2
+
+[9530]
+InfoOutput=2
+
+[9531]
+InfoOutput=2
+
+[9532]
+InfoOutput=2
+
+[AkonadiAgentServer]
+InfoOutput=2
+
+[KSharedDataCache]
+InfoOutput=4
+
+[Oxygen ( style )]
+InfoOutput=2
+
+[akonadi_archivemail_agent]
+InfoOutput=2
+
+[akonadi_folderarchive_agent]
+InfoOutput=2
+
+[akonadi_maildispatcher_agent]
+InfoOutput=2
+
+[akonadi_mailfilter_agent]
+InfoOutput=2
+
+[akonadi_migration_agent]
+InfoOutput=2
+
+[akonadi_nepomuk_feeder]
+InfoOutput=2
+
+[akonadiconsole]
+InfoOutput=2
+
+[kbuildsycoca4]
+InfoOutput=2
+
+[kdecore (KConfigSkeleton)]
+InfoOutput=2
+
+[unnamed app]
+InfoOutput=2


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic