From kde-commits Thu Oct 31 21:45:18 2013 From: Sergio Martins Date: Thu, 31 Oct 2013 21:45:18 +0000 To: kde-commits Subject: [kdepimlibs/KDE/4.11] akonadi/calendar/tests: sync the unit-tests with master. Message-Id: X-MARC-Message: https://marc.info/?l=kde-commits&m=138325593207060 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_rec= id01 A +25 -0 akonadi/calendar/tests/itip_data/invited_us_daily_update01 A +26 -0 akonadi/calendar/tests/itip_data/invited_us_daily_update_rec= id01 A +23 -0 akonadi/calendar/tests/itip_data/invited_us_update01 A +616 -0 akonadi/calendar/tests/itiphandlertest.cpp [License: LGP= L (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/akon= adi_maildir_resource_0rc D +0 -2 akonadi/calendar/tests/unittestenv/kdehome/share/config/akon= adi_mailtransport_dummy_resource_0rc A +1672 -0 akonadi/calendar/tests/unittestenv/kdehome/share/config/kdeb= ugrc 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 whic= h are listed at that page. http://commits.kde.org/kdepimlibs/d662dbc0c4947b3cffacc4410f5852710a6df481 diff --git a/akonadi/calendar/tests/helper.cpp b/akonadi/calendar/tests/hel= per.cpp new file mode 100644 index 0000000..a152345 --- /dev/null +++ b/akonadi/calendar/tests/helper.cpp @@ -0,0 +1,41 @@ +#include "helper.h" + +#include +#include +#include + +#include +#include + +using namespace Akonadi; + +bool Helper::confirmExists(const Akonadi::Item &item) +{ + ItemFetchJob *job =3D new ItemFetchJob(item); + return job->exec() !=3D 0; +} + +bool Helper::confirmDoesntExist(const Akonadi::Item &item) +{ + ItemFetchJob *job =3D new ItemFetchJob(item); + return job->exec() =3D=3D 0; +} + + +Akonadi::Collection Helper::fetchCollection() +{ + CollectionFetchJob *job =3D new CollectionFetchJob(Collection::root(), + CollectionFetchJob::R= ecursive); + // Get list of collections + job->fetchScope().setContentMimeTypes(QStringList() << QLatin1String("= application/x-vnd.akonadi.calendar.event")); + const bool ret =3D job->exec(); + Q_ASSERT(ret); + + // Find our collection + Collection::List collections =3D job->collections(); + Collection collection =3D collections.first(); + + Q_ASSERT(collection.isValid()); + + return collection; +} diff --git a/akonadi/calendar/tests/helper.h b/akonadi/calendar/tests/helpe= r.h new file mode 100644 index 0000000..2aee89b --- /dev/null +++ b/akonadi/calendar/tests/helper.h @@ -0,0 +1,32 @@ +/* + Copyright (c) 2013 S=C3=A9rgio Martins + + 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 WI= THOUT + 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 Lice= nse + along with this library; see the file COPYING.LIB. If not, write to t= he + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Bosto= n, MA + 02110-1301, USA. +*/ + +#ifndef HELPER_H_ +#define HELPER_H_ + +#include +#include + +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/test= s/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 #include @@ -25,7 +26,6 @@ #include #include #include - #include = #include @@ -35,17 +35,6 @@ using namespace KCalCore; = Q_DECLARE_METATYPE(QList) = -static bool confirmExists(const Akonadi::Item &item) -{ - ItemFetchJob *job =3D new ItemFetchJob(item); - return job->exec() !=3D 0; -} - -static bool confirmDoesntExists(const Akonadi::Item &item) -{ - ItemFetchJob *job =3D new ItemFetchJob(item); - return job->exec() =3D=3D 0; -} = static bool checkSummary(const Akonadi::Item &item, const QString &expecte= d) { @@ -85,48 +74,12 @@ static Akonadi::Item createItem(const Akonadi::Collecti= on &collection) return createJob->item(); } = -void HistoryTest::createIncidence(const QString &uid) -{ - Item item; - item.setMimeType(Event::eventMimeType()); - Incidence::Ptr incidence =3D Incidence::Ptr(new Event()); - incidence->setUid(uid); - incidence->setSummary(QLatin1String("summary")); - item.setPayload(incidence); - ItemCreateJob *job =3D new ItemCreateJob(item, mCollection, this); - AKVERIFYEXEC(job); -} - -void HistoryTest::fetchCollection() -{ - CollectionFetchJob *job =3D new CollectionFetchJob(Collection::root(), - CollectionFetchJob::R= ecursive, - this); - // Get list of collections - job->fetchScope().setContentMimeTypes(QStringList() << QLatin1String("= application/x-vnd.akonadi.calendar.event")); - AKVERIFYEXEC(job); - - // Find our collection - Collection::List collections =3D job->collections(); - QVERIFY(!collections.isEmpty()); - mCollection =3D collections.first(); - - QVERIFY(mCollection.isValid()); -} - void HistoryTest::initTestCase() { AkonadiTest::checkTestIsIsolated(); = - fetchCollection(); - qRegisterMetaType("Akonadi::Item"); - qRegisterMetaType >("QLis= t"); - qRegisterMetaType >("QVector"); - mChanger =3D new IncidenceChanger(this); - mChanger->setShowDialogsOnError(false); - mChanger->setHistoryEnabled(true); mHistory =3D mChanger->history(); - mChanger->setDefaultCollection(mCollection); + connect(mChanger, SIGNAL(createFinished(int,Akonadi::Item,Akonadi::IncidenceCha= nger::ResultCode,QString)), SLOT(createFinished(int,Akonadi::Item,Akonadi::IncidenceChang= er::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] =3D 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 mPendingSignals; QHash mItemByChangeId; QList mKnownChangeIds; = - void createIncidence(const QString &uid); - void fetchCollection(); - private Q_SLOTS: void initTestCase(); = diff --git a/akonadi/calendar/tests/incidencechangertest.cpp b/akonadi/cale= ndar/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::Destinati= onPolicyDefault << false << IncidenceChanger::= ResultCodeSuccess; = + // In this case, the collection dialog shouldn't be shown, as we onl= y have 1 collection + QTest::newRow( "Only one collection" ) << false << "SomeUid6" << "Su= mmary6" << Collection() + << Collection() << true + << IncidenceChanger::Destinat= ionPolicyAsk + << false << IncidenceChanger:= :ResultCodeSuccess; + Collection collectionWithoutRights =3D Collection( mCollection.id() = ); collectionWithoutRights.setRights( Collection::Rights() ); Q_ASSERT( ( mCollection.rights() & Akonadi::Collection::CanCreateIte= m ) ); @@ -250,7 +256,7 @@ class IncidenceChangerTest : public QObject Item::List items =3D fetchJob->items(); = // 5 Incidences were created in testCreating(). Keep this in sync. - QVERIFY( items.count() =3D=3D 4 ); + QCOMPARE( items.count(), 5 ); QTest::newRow( "Simple delete" ) << (Item::List() << items.at( 0 ) )= << true << false << IncidenceChanger::ResultCodeSucc= ess; = 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=3DYEARLY;INTERVAL=3D1;BYDAY=3D2SU;BYMONTH=3D3 +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +TZNAME:EST +DTSTART:19701101T020000 +RRULE:FREQ=3DYEARLY;INTERVAL=3D1;BYDAY=3D1SU;BYMONTH=3D11 +END:STANDARD +END:VTIMEZONE + +BEGIN:VEVENT +DTSTART:20100430T140000Z +DTEND:20100430T150000Z +ORGANIZER;RSVP=3DTRUE;PARTSTAT=3DACCEPTED;ROLE=3DCHAIR:mailto:xyz@yahoo.ca +UID:b6f0466a-8877-49d0-a4fc-8ee18ffd8e07 +ATTENDEE;RSVP=3DTRUE;CN=3DXYZ;PARTSTAT=3DNEEDS-ACTION; + ROLE=3DREQ-PARTICIPANT:mailto:mailto:unittests@dev.nul +ATTENDEE;RSVP=3DTRUE;CN=3DXYZ;PARTSTAT=3DNEEDS-ACTION; + ROLE=3DREQ-PARTICIPANT:mailto:xyz@pqr.com +ATTENDEE;RSVP=3DTRUE;CN=3D'XYZ';PARTSTAT=3DNEEDS-ACTION; + ROLE=3DREQ-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 futuredep= loyment steps\, production environment +TRANSP:OPAQUE +END:VEVENT +END:VCALENDAR diff --git a/akonadi/calendar/tests/itip_data/expected_data/cancel1 b/akona= di/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=3DTRUE;PARTSTAT=3DACCEPTED;ROLE=3DREQ-PARTICIPANT; + X-UID=3Dtheir-email@dev.nul:mailto:their-email@dev.nul +ATTENDEE;CN=3D"unittests@dev.nul";RSVP=3DTRUE;PARTSTAT=3DACCEPTED; + ROLE=3DREQ-PARTICIPANT;X-UID=3Dunittests@dev.nul:mailto:unittests@dev.nul +CREATED:20131022T230432Z +UID:uosj936i6arrtl9c2i5r2mfuvg +LAST-MODIFIED:20131025T103442Z +DESCRIPTION:Foo +SUMMARY:Daily stuff +STATUS:CONFIRMED +RRULE:FREQ=3DDAILY +DTSTART:20131022T090000Z +DTEND:20131022T100000Z +TRANSP:OPAQUE +END:VEVENT +BEGIN:VEVENT +ORGANIZER:MAILTO:their-email@dev.nul +DTSTAMP:20131025T103442Z +ATTENDEE;RSVP=3DTRUE;PARTSTAT=3DACCEPTED;ROLE=3DREQ-PARTICIPANT; + X-UID=3Dtheir-email@dev.nul:mailto:their-email@dev.nul +ATTENDEE;RSVP=3DTRUE;PARTSTAT=3DACCEPTED;ROLE=3DREQ-PARTICIPANT; + X-UID=3Dunittests@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/akona= di/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=3D"iamsergio@gmail.com":MAILTO:iamsergio@gmail.com +DTSTAMP:20131025T103442Z +ATTENDEE;RSVP=3DTRUE;PARTSTAT=3DACCEPTED;ROLE=3DREQ-PARTICIPANT; + X-UID=3D140218346340032:mailto:their-email@dev.nul +ATTENDEE;CN=3D"sergio.martins@kdab.com";RSVP=3DTRUE;PARTSTAT=3DACCEPTED; + ROLE=3DREQ-PARTICIPANT;X-UID=3D140218346000928: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/akona= di/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=3DTRUE;PARTSTAT=3DACCEPTED;ROLE=3DREQ-PARTICIPANT; + X-UID=3D140218346311392:mailto:their-email@dev.nul +ATTENDEE;CN=3D"unittests@dev.nul";RSVP=3DTRUE;PARTSTAT=3DACCEPTED; + ROLE=3DREQ-PARTICIPANT;X-UID=3D140218344168032:mailto:unittests@dev.nul +CREATED:20131023T175039Z +UID:uosj936i6arrtl9c2i5r2mfuvg +SEQUENCE:2 +LAST-MODIFIED:20131025T103442Z +DESCRIPTION:Foo +SUMMARY:new-summary +STATUS:CONFIRMED +RRULE:FREQ=3DDAILY +DTSTART:20131022T090000Z +DTEND:20131022T100000Z +TRANSP:OPAQUE +END:VEVENT +END:VCALENDAR diff --git a/akonadi/calendar/tests/itip_data/expected_data/update3 b/akona= di/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=3DTRUE;PARTSTAT=3DACCEPTED;ROLE=3DREQ-PARTICIPANT; + X-UID=3D140218344167648:mailto:their-email@dev.nul +ATTENDEE;CN=3D"unittests@dev.nul";RSVP=3DTRUE;PARTSTAT=3DACCEPTED; + ROLE=3DREQ-PARTICIPANT;X-UID=3D140218344958464:mailto:unittests@dev.nul +CREATED:20131022T230432Z +UID:uosj936i6arrtl9c2i5r2mfuvg +LAST-MODIFIED:20131025T103442Z +DESCRIPTION:Foo +SUMMARY:Daily stuff +STATUS:CONFIRMED +RRULE:FREQ=3DDAILY +DTSTART:20131022T090000Z +DTEND:20131022T100000Z +TRANSP:OPAQUE +END:VEVENT +BEGIN:VEVENT +ORGANIZER:MAILTO:their-email@dev.nul +DTSTAMP:20131025T103442Z +ATTENDEE;RSVP=3DTRUE;PARTSTAT=3DACCEPTED;ROLE=3DREQ-PARTICIPANT; + X-UID=3D140218346119456:mailto:their-email@dev.nul +ATTENDEE;CN=3D"unittests@dev.nul";RSVP=3DTRUE;PARTSTAT=3DACCEPTED; + ROLE=3DREQ-PARTICIPANT;X-UID=3D140218346001408: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=3DDAILY +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=3Dtheir-email@dev.nul:mailto:their-email@dev.nul +UID:uosj936i6arrtl9c2i5r2mfuvg +ATTENDEE;CUTYPE=3DINDIVIDUAL;ROLE=3DREQ-PARTICIPANT;PARTSTAT=3DACCEPTED;RS= VP=3DTRUE;X-NUM-GUESTS=3D0:mailto:their-email@dev.nul +ATTENDEE;CUTYPE=3DINDIVIDUAL;ROLE=3DREQ-PARTICIPANT;PARTSTAT=3DNEEDS-ACTIO= N;RSVP=3DTRUE;CN=3Dsergio.martins@kdab.com;X-NUM-GUESTS=3D0:mailto:unittest= s@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=3Dtheir-email@dev.nul:mailto:their-email@dev.nul +UID:uosj936i6arrtl9c2i5r2mfuvg +ATTENDEE;CUTYPE=3DINDIVIDUAL;ROLE=3DREQ-PARTICIPANT;PARTSTAT=3DACCEPTED;X-= NUM-GUE + STS=3D0:mailto:their-email@dev.nul +ATTENDEE;CUTYPE=3DINDIVIDUAL;ROLE=3DREQ-PARTICIPANT;PARTSTAT=3DNEEDS-ACTIO= N;CN=3Dunittests@dev.nul;X-NUM-GUESTS=3D0: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/ca= lendar/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=3DDAILY +DTSTAMP:20131022T230432Z +ORGANIZER:mailto:their-email@dev.nul +UID:uosj936i6arrtl9c2i5r2mfuvg +ATTENDEE;CUTYPE=3DINDIVIDUAL;ROLE=3DREQ-PARTICIPANT;PARTSTAT=3DACCEPTED;RS= VP=3DTRUE + ;X-NUM-GUESTS=3D0:mailto:their-email@dev.nul +ATTENDEE;CUTYPE=3DINDIVIDUAL;ROLE=3DREQ-PARTICIPANT;PARTSTAT=3DNEEDS-ACTIO= N;RSVP=3D + TRUE;CN=3Dunittests@dev.nul;X-NUM-GUESTS=3D0: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/a= konadi/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=3DYEARLY;BYMONTH=3D3;BYDAY=3D-1SU +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+0100 +TZOFFSETTO:+0000 +TZNAME:GMT +DTSTART:19701025T020000 +RRULE:FREQ=3DYEARLY;BYMONTH=3D10;BYDAY=3D-1SU +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +DTSTART;TZID=3DEurope/London:20131022T090000 +DTEND;TZID=3DEurope/London:20131022T100000 +RRULE:FREQ=3DDAILY +DTSTAMP:20131022T232159Z +ORGANIZER:mailto:their-email@dev.nul +UID:uosj936i6arrtl9c2i5r2mfuvg +ATTENDEE;CUTYPE=3DINDIVIDUAL;ROLE=3DREQ-PARTICIPANT;PARTSTAT=3DACCEPTED;X-= NUM-GUE + STS=3D0:mailto:their-email@dev.nul +ATTENDEE;CUTYPE=3DINDIVIDUAL;ROLE=3DREQ-PARTICIPANT;PARTSTAT=3DNEEDS-ACTIO= N;CN=3Dunittests@dev.nul;X-NUM-GUESTS=3D0: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_recid= 01 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=3DTRUE;PARTSTAT=3DACCEPTED;ROLE=3DREQ-PARTICIPANT; + X-UID=3D140218344167648:mailto:their-email@dev.nul +ATTENDEE;RSVP=3DTRUE: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/a= konadi/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=3DDAILY +DTSTAMP:20131023T175057Z +ORGANIZER:mailto:their-email@dev.nul +UID:uosj936i6arrtl9c2i5r2mfuvg +ATTENDEE;CUTYPE=3DINDIVIDUAL;ROLE=3DREQ-PARTICIPANT;PARTSTAT=3DACCEPTED;RS= VP=3DTRUE + ;X-NUM-GUESTS=3D0:mailto:their-email@dev.nul +ATTENDEE;CUTYPE=3DINDIVIDUAL;ROLE=3DREQ-PARTICIPANT;PARTSTAT=3DNEEDS-ACTIO= N;RSVP=3D + TRUE;CN=3Dunittests@dev.nul;X-NUM-GUESTS=3D0: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_recid= 01 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=3DDAILY +DTSTAMP:20131023T175057Z +ORGANIZER:mailto:their-email@dev.nul +UID:uosj936i6arrtl9c2i5r2mfuvg +ATTENDEE;CUTYPE=3DINDIVIDUAL;ROLE=3DREQ-PARTICIPANT;PARTSTAT=3DACCEPTED;RS= VP=3DTRUE + ;X-NUM-GUESTS=3D0:mailto:their-email@dev.nul +ATTENDEE;CUTYPE=3DINDIVIDUAL;ROLE=3DREQ-PARTICIPANT;PARTSTAT=3DNEEDS-ACTIO= N;RSVP=3D + TRUE;CN=3Dunittests@dev.nul;X-NUM-GUESTS=3D0: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=3Diamsergio@gmail.com:mailto:iamsergio@gmail.com +UID:uosj936i6arrtl9c2i5r2mfuvg +ATTENDEE;CUTYPE=3DINDIVIDUAL;ROLE=3DREQ-PARTICIPANT;PARTSTAT=3DACCEPTED;RS= VP=3DTRUE;X-NUM-GUESTS=3D0:mailto:their-email@dev.nul +ATTENDEE;CUTYPE=3DINDIVIDUAL;ROLE=3DREQ-PARTICIPANT;PARTSTAT=3DNEEDS-ACTIO= N;RSVP=3DTRUE;CN=3Dsergio.martins@kdab.com;X-NUM-GUESTS=3D0:mailto:unittest= s@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=C3=A9rgio Martins + + 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 WI= THOUT + 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 Lice= nse + along with this library; see the file COPYING.LIB. If not, write to t= he + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Bosto= n, MA + 02110-1301, USA. +*/ + +#include "itiphandlertest.h" +#include "helper.h" +#include "../mailclient_p.h" +#include "../fetchjobcalendar.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +using namespace Akonadi; +using namespace KCalCore; + +Q_DECLARE_METATYPE(Akonadi::IncidenceChanger::InvitationPolicy) +Q_DECLARE_METATYPE(QList) +Q_DECLARE_METATYPE(Akonadi::ITIPHandler::Result) +Q_DECLARE_METATYPE(KCalCore::Attendee::PartStat) +Q_DECLARE_METATYPE(QList) + +static const char *s_ourEmail =3D "unittests@dev.nul"; // change also in k= depimlibs/akonadi/calendar/tests/unittestenv/kdehome/share/config + +void ITIPHandlerTest::initTestCase() +{ + AkonadiTest::checkTestIsIsolated(); + m_pendingItipMessageSignal =3D 0; + m_pendingIncidenceChangerSignal =3D 0; + MailClient::sRunningUnitTests =3D true; + m_itipHandler =3D 0; + m_changer =3D 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::In= cidenceChanger::ResultCode,QString)), + SLOT(onCreateFinished(int,Akonadi::Item,Akonadi::IncidenceChan= ger::ResultCode,QString)) ); + + connect(m_changer, SIGNAL(deleteFinished(int,QVector,Akonadi::IncidenceChanger::ResultCode,QString)), + SLOT(onDeleteFinished(int,QVector,Akonadi::= IncidenceChanger::ResultCode,QString)) ); + + connect(m_changer,SIGNAL(modifyFinished(int,Akonadi::Item,Akonadi::Inc= idenceChanger::ResultCode,QString)), + SLOT(onModifyFinished(int,Akonadi::Item,Akonadi::IncidenceChan= ger::ResultCode,QString)) ); +} + +void ITIPHandlerTest::testProcessITIPMessage_data() +{ + QTest::addColumn("data_filename"); + QTest::addColumn("action"); + QTest::addColumn("receiver"); + QTest::addColumn("incidenceUid"); // uid of incidence in invi= tation + QTest::addColumn("expectedResult"); + QTest::addColumn("expectedNumIncidences"); + QTest::addColumn("expectedPartStat"); + + QString data_filename; + QString action =3D QLatin1String("accepted"); + QString incidenceUid =3D QString::fromLatin1("uosj936i6arrtl9c2i5r2mfu= vg"); + QString receiver =3D QLatin1String(s_ourEmail); + Akonadi::ITIPHandler::Result expectedResult; + int expectedNumIncidences =3D 0; + KCalCore::Attendee::PartStat expectedPartStat; + + //--------------------------------------------------------------------= -------------------------- + // Someone invited us to an event, and we accept + expectedResult =3D ITIPHandler::ResultSuccess; + data_filename =3D QLatin1String("invited_us"); + expectedNumIncidences =3D 1; + expectedPartStat =3D KCalCore::Attendee::Accepted; + action =3D 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 =3D ITIPHandler::ResultSuccess; + data_filename =3D QLatin1String("invited_us"); + expectedNumIncidences =3D 1; + expectedPartStat =3D KCalCore::Attendee::Tentative; + action =3D QLatin1String("tentative"); + QTest::newRow("invited us2") << data_filename << action << receiver <<= incidenceUid + << expectedResult + << expectedNumIncidences + << expectedPartStat; + //--------------------------------------------------------------------= -------------------------- + // Someone invited us to an event, we delegate it + expectedResult =3D ITIPHandler::ResultSuccess; + data_filename =3D QLatin1String("invited_us"); + + // The e-mail to the delegate is sent by kmail's text_calendar.cpp + expectedNumIncidences =3D 1; + expectedPartStat =3D KCalCore::Attendee::Delegated; + action =3D 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 =3D ITIPHandler::ResultSuccess; + data_filename =3D QLatin1String("invited_us"); + expectedNumIncidences =3D 0; + action =3D 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 =3D ITIPHandler::ResultError; + expectedNumIncidences =3D 0; + action =3D QLatin1String("accepted"); + QTest::newRow("invalid data") << QString() << action << receiver << in= cidenceUid + << expectedResult + << expectedNumIncidences + << expectedPartStat; + //--------------------------------------------------------------------= -------------------------- + // Testing invalid action + expectedResult =3D ITIPHandler::ResultError; + data_filename =3D QLatin1String("invitation_us"); + expectedNumIncidences =3D 0; + action =3D QLatin1String("accepted"); + QTest::newRow("invalid action") << data_filename << QString() << recei= ver << incidenceUid + << expectedResult + << expectedNumIncidences + << expectedPartStat; + //--------------------------------------------------------------------= -------------------------- + // Test bug 235749 + expectedResult =3D ITIPHandler::ResultSuccess; + data_filename =3D QLatin1String("bug235749"); + expectedNumIncidences =3D 1; + expectedPartStat =3D KCalCore::Attendee::Accepted; + action =3D QLatin1String("accepted"); + incidenceUid =3D 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 =3D ITIPHandler::ResultError; + data_filename =3D QLatin1String("invited_us"); + expectedNumIncidences =3D 0; + expectedPartStat =3D KCalCore::Attendee::Accepted; + action =3D QLatin1String("counter"); + incidenceUid =3D 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 =3D expectedResult; + + QString iCalData =3D icalData(data_filename); + Akonadi::Item::List items; + processItip(iCalData, receiver, action, expectedNumIncidences, items); + + if (expectedNumIncidences =3D=3D 1) { + KCalCore::Incidence::Ptr incidence =3D items.first().payload(); + QVERIFY(incidence); + QCOMPARE(incidence->schedulingID(), incidenceUid); + QVERIFY(incidence->schedulingID() !=3D incidence->uid()); + + KCalCore::Attendee::Ptr me =3D ourAttendee(incidence); + QVERIFY(me); + QCOMPARE(me->status(), expectedPartStat); + } + + cleanup(); +} + +void ITIPHandlerTest::testProcessITIPMessages_data() +{ + QTest::addColumn("invitation_filenames"); // filename to = create incidence (inputs) + QTest::addColumn("expected_filename"); // filename with expec= ted data (reference) + QTest::addColumn("actions"); // we must specify the METHO= D. This is an ITipHandler API workaround, not sure why we must pass it as a= rgument 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 e= vent, and we record update: + invitation_filenames.clear(); + invitation_filenames << QLatin1String("invited_us") << QLatin1String("= invited_us_update01"); + expected_filename =3D QLatin1String("expected_data/update1"); + QTest::newRow("accept update") << invitation_filenames << expected_fil= ename << actions; + //--------------------------------------------------------------------= -------------------------- + // Someone invited us to an event, we accept, then organizer changes e= vent, and we record update: + invitation_filenames.clear(); + invitation_filenames << QLatin1String("invited_us") << QLatin1String("= invited_us_daily_update01"); + expected_filename =3D QLatin1String("expected_data/update2"); + QTest::newRow("accept recurringupdate") << invitation_filenames << exp= ected_filename << actions; + //--------------------------------------------------------------------= -------------------------- + // We accept a recurring event, then the organizer changes the summary= to the second instance (RECID) + expected_filename =3D QLatin1String("expected_data/update3"); + invitation_filenames.clear(); + invitation_filenames << QLatin1String("invited_us_daily") << QLatin1St= ring("invited_us_daily_update_recid01"); + QTest::newRow("accept recid update") << invitation_filenames << expect= ed_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 crea= ted, and our main incidence + // should not be touched + invitation_filenames.clear(); + invitation_filenames << QLatin1String("invited_us_daily") << QLatin1St= ring("invited_us_daily_cancel_recid01"); + expected_filename =3D QLatin1String("expected_data/cancel1"); + actions << QLatin1String("accepted") << QLatin1String("cancel"); + QTest::newRow("accept recid cancel") << invitation_filenames << expect= ed_filename << actions; + + //--------------------------------------------------------------------= -------------------------- +} + +void ITIPHandlerTest::testProcessITIPMessages() +{ + QFETCH(QStringList, invitation_filenames); + QFETCH(QString, expected_filename); + QFETCH(QStringList, actions); + + const QString receiver =3D QLatin1String(s_ourEmail); + + MailClient::sUnitTestResults.clear(); + createITIPHandler(); + + m_expectedResult =3D Akonadi::ITIPHandler::ResultSuccess; + + for (int i=3D0; i("creation_data_filename"); // filename to cr= eate incidence + QTest::addColumn("cancel_data_filename"); // filename with in= cidence cancelation + QTest::addColumn("incidenceUid"); // uid of incidence in invi= tation + + + QString creation_data_filename; + QString cancel_data_filename; + QString incidenceUid =3D QString::fromLatin1("uosj936i6arrtl9c2i5r2mfu= vg"); + //--------------------------------------------------------------------= -------------------------- + // Someone invited us to an event, we accept, then organizer cancels e= vent + creation_data_filename =3D QLatin1String("invited_us"); + cancel_data_filename =3D QLatin1String("invited_us_cancel01"); + + QTest::newRow("cancel1") << creation_data_filename << cancel_data_file= name + << incidenceUid; + //--------------------------------------------------------------------= -------------------------- + // Someone invited us to daily event, we accept, then organizer cancel= s the whole recurrence series + creation_data_filename =3D QLatin1String("invited_us_daily"); + cancel_data_filename =3D 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 =3D QLatin1String(s_ourEmail); + MailClient::sUnitTestResults.clear(); + createITIPHandler(); + + m_expectedResult =3D Akonadi::ITIPHandler::ResultSuccess; + + // First accept the invitation that creates the incidence: + QString iCalData =3D icalData(creation_data_filename); + Item::List items; + processItip(iCalData, receiver, QLatin1String("accepted"), 1, items); + + KCalCore::Incidence::Ptr incidence =3D items.first().payload(); + QVERIFY(incidence); + + // good, now accept the invitation that has the CANCEL + iCalData =3D icalData(cancel_data_filename); + processItip(iCalData, receiver, QLatin1String("accepted"), 0, items); +} + +void ITIPHandlerTest::testOutgoingInvitations_data() +{ + QTest::addColumn("item"); // existing incidence that wi= ll be target of creation, deletion or modification + QTest::addColumn("changeType");= // creation, deletion, modification + QTest::addColumn("expectedEmailCount"); + QTest::addColumn("invitationPolicy= "); + + Akonadi::Item item; + KCalCore::Incidence::Ptr incidence; + IncidenceChanger::ChangeType changeType; + const IncidenceChanger::InvitationPolicy invitationPolicyAsk =3D I= ncidenceChanger::InvitationPolicyAsk; + const IncidenceChanger::InvitationPolicy invitationPolicySend =3D = IncidenceChanger::InvitationPolicySend; + const IncidenceChanger::InvitationPolicy invitationPolicyDontSend =3D = IncidenceChanger::InvitationPolicyDontSend; + int expectedEmailCount =3D 0; + Q_UNUSED(invitationPolicyAsk); + + const QString ourEmail =3D QLatin1String(s_ourEmail); + const Attendee::Ptr us =3D Attendee::Ptr(new Attendee(QString(), ourEm= ail)); + const Attendee::Ptr mia =3D Attendee::Ptr(new Attendee(QLatin1String("= Mia Wallace"), QLatin1String("mia@dev.nul"))); + const Attendee::Ptr vincent =3D Attendee::Ptr(new Attendee(QLatin1Stri= ng("Vincent"), QLatin1String("vincent@dev.nul"))); + const Attendee::Ptr jules =3D Attendee::Ptr(new Attendee(QLatin1String= ("Jules"), QLatin1String("jules@dev.nul"))); + const QString uid =3D QLatin1String("random-uid-123"); + + //--------------------------------------------------------------------= -------------------------- + // Creation. We are organizer. We invite another person. + changeType =3D IncidenceChanger::ChangeTypeCreate; + item =3D generateIncidence(uid, /**organizer=3D*/ourEmail); + incidence =3D item.payload(); + incidence->addAttendee(vincent); + incidence->addAttendee(jules); + expectedEmailCount =3D 1; + QTest::newRow("Creation. We organize.") << item << changeType << expec= tedEmailCount << invitationPolicySend; + //--------------------------------------------------------------------= -------------------------- + // Creation. We are organizer. We invite another person. But we choose= not to send invitation e-mail. + changeType =3D IncidenceChanger::ChangeTypeCreate; + item =3D generateIncidence(uid, /**organizer=3D*/ourEmail); + incidence =3D item.payload(); + incidence->addAttendee(vincent); + incidence->addAttendee(jules); + expectedEmailCount =3D 0; + QTest::newRow("Creation. We organize.2") << item << changeType << expe= ctedEmailCount << invitationPolicyDontSend; + //--------------------------------------------------------------------= -------------------------- + // We delete an event that we organized, and has attendees, that will = be notified. + changeType =3D IncidenceChanger::ChangeTypeDelete; + item =3D generateIncidence(uid, /**organizer=3D*/ourEmail); + incidence =3D item.payload(); + incidence->addAttendee(vincent); + incidence->addAttendee(jules); + expectedEmailCount =3D 1; + QTest::newRow("Deletion. We organized.") << item << changeType << expe= ctedEmailCount << invitationPolicySend; + //--------------------------------------------------------------------= -------------------------- + // We delete an event that we organized, and has attendees. We won't s= end e-mail notifications. + changeType =3D IncidenceChanger::ChangeTypeDelete; + item =3D generateIncidence(uid, /**organizer=3D*/ourEmail); + incidence =3D item.payload(); + incidence->addAttendee(vincent); + incidence->addAttendee(jules); + expectedEmailCount =3D 0; + QTest::newRow("Deletion. We organized.2") << item << changeType << exp= ectedEmailCount << invitationPolicyDontSend; + //--------------------------------------------------------------------= -------------------------- + // We delete an event that we organized, and has attendees, who will b= e notified. + changeType =3D IncidenceChanger::ChangeTypeModify; + item =3D generateIncidence(uid, /**organizer=3D*/ourEmail); + incidence =3D item.payload(); + incidence->addAttendee(vincent); + incidence->addAttendee(jules); + expectedEmailCount =3D 1; + QTest::newRow("Modification. We organizd.") << item << changeType << e= xpectedEmailCount << invitationPolicySend; + //--------------------------------------------------------------------= -------------------------- + // We delete an event that we organized, and has attendees, who wont b= e notified. + changeType =3D IncidenceChanger::ChangeTypeModify; + item =3D generateIncidence(uid, /**organizer=3D*/ourEmail); + incidence =3D item.payload(); + incidence->addAttendee(vincent); // TODO: test that all attendees got = the e-mail + incidence->addAttendee(jules); + expectedEmailCount =3D 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=3DDeclined + changeType =3D IncidenceChanger::ChangeTypeDelete; + item =3D generateIncidence(uid, /**organizer=3D*/mia->email()); + incidence =3D item.payload(); + incidence->addAttendee(vincent); + incidence->addAttendee(jules); + us->setStatus(Attendee::Accepted); // TODO: Test without accepted stat= us + incidence->addAttendee(us); // TODO: test that attendees didn't receiv= e the REPLY + expectedEmailCount =3D 1; // REPLY is always sent, there are no dialog= s 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=3DDeclined + changeType =3D IncidenceChanger::ChangeTypeDelete; + item =3D generateIncidence(uid, /**organizer=3D*/mia->email()); + incidence =3D item.payload(); + incidence->addAttendee(vincent); + incidence->addAttendee(jules); // TODO: test that attendees didn't rec= eive the REPLY + us->setStatus(Attendee::Accepted); // TODO: Test without accepted stat= us + incidence->addAttendee(us); + expectedEmailCount =3D 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 =3D item.payload(); + + m_pendingIncidenceChangerSignal =3D 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 groupwa= re because creating an incidence which we're not the organizer of is not pe= rmitted. + m_changer->createIncidence(incidence, mCollection); + waitForIt(); + m_changer->setGroupwareCommunication(true); + QCOMPARE(MailClient::sUnitTestResults.count(), 0); + QVERIFY(mLastInsertedItem.isValid()); + m_pendingIncidenceChangerSignal =3D 1; + Incidence::Ptr oldIncidence =3D Incidence::Ptr(incidence->clone()); + incidence->setSummary(QLatin1String("the-new-summary")); + int changeId =3D m_changer->modifyIncidence(mLastInsertedItem, old= Incidence); + QVERIFY(changeId !=3D 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 =3D 1; + m_changer->deleteIncidence(mLastInsertedItem); + waitForIt(); + QCOMPARE(MailClient::sUnitTestResults.count(), expectedEmailCount); + break; + default: + Q_ASSERT(false); + } + +} + +void ITIPHandlerTest::cleanup() +{ + Akonadi::Item::List items =3D calendarItems(); + foreach (const Akonadi::Item &item, items) { + ItemDeleteJob *job =3D new ItemDeleteJob(item); + AKVERIFYEXEC(job); + } + + delete m_itipHandler; + m_itipHandler =3D 0; +} + +void ITIPHandlerTest::createITIPHandler() +{ + m_itipHandler =3D new Akonadi::ITIPHandler(); + m_itipHandler->setShowDialogsOnError(false); + connect(m_itipHandler, SIGNAL(iTipMessageProcessed(Akonadi::ITIPHandle= r::Result,QString)), + SLOT(oniTipMessageProcessed(Akonadi::ITIPHandler::Result,QStri= ng)) ); +} + +QString ITIPHandlerTest::icalData(const QString &data_filename) +{ + QString absolutePath =3D 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 expectedNumIn= cidences, + Akonadi::Item::List &items) +{ + items.clear(); + m_pendingItipMessageSignal =3D 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 =3D calendarItems(); + + if (expectedNumIncidences !=3D -1) { + QCOMPARE(items.count(), expectedNumIncidences); + } +} + +Attendee::Ptr ITIPHandlerTest::ourAttendee(const KCalCore::Incidence::Ptr = &incidence) const +{ + KCalCore::Attendee::List attendees =3D incidence->attendees(); + KCalCore::Attendee::Ptr me; + foreach (const KCalCore::Attendee::Ptr &attendee, attendees) { + if (attendee->email() =3D=3D QLatin1String(s_ourEmail)) { + me =3D attendee; + break; + } + } + + return me; +} + +void ITIPHandlerTest::oniTipMessageProcessed(ITIPHandler::Result result, c= onst QString &errorMessage) +{ + if (result !=3D ITIPHandler::ResultSuccess && result !=3D m_expectedRe= sult) { + qDebug() << "ITIPHandlerTest::oniTipMessageProcessed() error =3D "= << errorMessage; + } + + m_pendingItipMessageSignal--; + QVERIFY(m_pendingItipMessageSignal >=3D 0); + if (m_pendingItipMessageSignal =3D=3D 0) { + stopWaiting(); + } + + QCOMPARE(m_expectedResult, result); +} + +void ITIPHandlerTest::onCreateFinished(int changeId, const Item &item, + IncidenceChanger::ResultCode result= Code, + const QString &errorString) +{ + Q_UNUSED(changeId); + Q_UNUSED(errorString); + mLastInsertedItem =3D item; + QCOMPARE(resultCode, IncidenceChanger::ResultCodeSuccess); + m_pendingIncidenceChangerSignal--; + QVERIFY(m_pendingIncidenceChangerSignal >=3D 0); + if (m_pendingIncidenceChangerSignal =3D=3D 0) { + stopWaiting(); + } +} + +void ITIPHandlerTest::onDeleteFinished(int changeId, const QVector &deletedIds, + IncidenceChanger::ResultCode result= Code, + const QString &errorString) +{ + Q_UNUSED(changeId); + Q_UNUSED(errorString); + Q_UNUSED(deletedIds); + QCOMPARE(resultCode, IncidenceChanger::ResultCodeSuccess); + m_pendingIncidenceChangerSignal--; + QVERIFY(m_pendingIncidenceChangerSignal >=3D 0); + if (m_pendingIncidenceChangerSignal =3D=3D 0) { + stopWaiting(); + } +} + +void ITIPHandlerTest::onModifyFinished(int changeId, const Item &item, + IncidenceChanger::ResultCode result= Code, + const QString &errorString) +{ + Q_UNUSED(changeId); + Q_UNUSED(errorString); + Q_UNUSED(item); + + QCOMPARE(resultCode, IncidenceChanger::ResultCodeSuccess); + m_pendingIncidenceChangerSignal--; + QVERIFY(m_pendingIncidenceChangerSignal >=3D 0); + if (m_pendingIncidenceChangerSignal =3D=3D 0) { + stopWaiting(); + } +} + +QTEST_AKONADIMAIN(ITIPHandlerTest, GUI) diff --git a/akonadi/calendar/tests/itiphandlertest.h b/akonadi/calendar/te= sts/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=C3=A9rgio Martins + + 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 WI= THOUT + 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 Lice= nse + along with this library; see the file COPYING.LIB. If not, write to t= he + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Bosto= n, MA + 02110-1301, USA. +*/ + +#ifndef ITIPHANDLER_TEST_H +#define ITIPHANDLER_TEST_H + +#include "../incidencechanger.h" +#include "../itiphandler.h" +#include "unittestbase.h" + +#include +#include + +#include +#include + + +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 modificat= ion, 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 &in= cidence) 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 &= 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/t= ests/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 #include #include +#include = #include = #include #include = +static const char *s_ourEmail =3D "unittests@dev.nul"; // change also in k= depimlibs/akonadi/calendar/tests/unittestenv/kdehome/share/config + using namespace Akonadi; = Q_DECLARE_METATYPE( KPIMIdentities::Identity ) @@ -55,6 +56,7 @@ private slots: = mPendingSignals =3D 0; mMailClient =3D new MailClient( this ); + mMailClient->sRunningUnitTests =3D true; mLastResult =3D MailClient::ResultSuccess; connect( mMailClient, SIGNAL(finished(Akonadi::MailClient::Result,QStr= ing)), SLOT(handleFinished(Akonadi::MailClient::Result,QString)) ); @@ -114,7 +116,7 @@ private slots: incidence->addAttendee( attendee ); incidence->setOrganizer( organizer ); expectedResult =3D MailClient::ResultSuccess; - toList << QLatin1String( "name1 " ); + toList << QLatin1String( "test@foo.org" ); QTest::newRow("One attendee") << incidence << identity << bccMe << att= achment << transport << expectedResult << expectedTransportId= << expectedFrom << toList << toCcList << toBccList; @@ -142,11 +144,11 @@ private slots: expectedResult =3D MailClient::ResultSuccess; // Should default to the default transport toBccList.clear(); - toBccList << QLatin1String( "Organizer " ); - QTest::newRow("Invalid transport") << incidence << identity << /*bccMe= */true << attachment - << transport << expectedResult - << expectedTransportId << expectedF= rom - << toList << toCcList << toBccList; + toBccList << QLatin1String( "unittests@dev.nul" ); + QTest::newRow("Test bcc") << incidence << identity << /*bccMe*/true <<= attachment + << transport << expectedResult + << expectedTransportId << expec= tedFrom + << toList << toCcList << toBccL= ist; //--------------------------------------------------------------------= -------------------------- // Test CC list attendee =3D KCalCore::Attendee::Ptr ( new KCalCore::Attendee( QLatin1= String( "name1" ), @@ -167,15 +169,15 @@ private slots: expectedResult =3D MailClient::ResultSuccess; // Should default to the default transport toBccList.clear(); - toBccList << QLatin1String( "Organizer " ); + toBccList << QLatin1String( "unittests@dev.nul" ); = toCcList.clear(); - toCcList << QLatin1String( "opt " ) - << QLatin1String( "non " ); - QTest::newRow("Invalid transport") << incidence << identity << /*bccMe= */true << attachment - << transport << expectedResult - << expectedTransportId << expectedF= rom - << toList << toCcList << toBccList; + toCcList << QLatin1String( "optional@foo.org" ) + << QLatin1String( "non@foo.org" ); + QTest::newRow("Test cc") << incidence << identity << /*bccMe*/true << = attachment + << transport << expectedResult + << expectedTransportId << expect= edFrom + << toList << toCcList << toBccLi= st; } = void testMailAttendees() @@ -191,6 +193,7 @@ private slots: QFETCH( QStringList, expectedToList ); QFETCH( QStringList, expectedCcList ); QFETCH( QStringList, expectedBccList ); + mMailClient->sUnitTestResults.clear(); = mPendingSignals =3D 1; mMailClient->mailAttendees( incidence, identity, bccMe, attachment, tr= ansport ); @@ -202,18 +205,23 @@ private slots: QVERIFY( false ); } = + UnitTestResult unitTestResult; + if ( mMailClient->sUnitTestResults.isEmpty() ) { + qDebug() << "mail results are empty"; + } else { + unitTestResult =3D mMailClient->sUnitTestResults.first(); + } = - if ( expectedTransportId !=3D -1 && - mMailClient->mUnitTestResult.transportId !=3D expectedTransportId= ) { - qDebug() << "got " << mMailClient->mUnitTestResult.transportId + if ( expectedTransportId !=3D -1 && unitTestResult.transportId !=3D ex= pectedTransportId ) { + qDebug() << "got " << unitTestResult.transportId << "; expected=3D" << 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 =3D QLatin1String( "from@kde.org" ); + const QString from =3D QLatin1String( s_ourEmail ); bool bccMe; QString attachment; QString subject =3D QLatin1String( "subject1" ); @@ -247,7 +255,7 @@ private slots: incidence->setOrganizer( organizer ); = QStringList toList; - toList << QLatin1String( "Organizer " ); + 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 =3D 1; mMailClient->mailOrganizer( incidence, identity, from, bccMe, attachme= nt, subject, transport ); waitForSignals(); QCOMPARE( mLastResult, expectedResult ); + + UnitTestResult unitTestResult =3D mMailClient->sUnitTestResults.first(= ); if ( expectedTransportId !=3D -1 ) - QCOMPARE( mMailClient->mUnitTestResult.transportId, expectedTranspor= tId ); + QCOMPARE( unitTestResult.transportId, expectedTransportId ); = - QCOMPARE( mMailClient->mUnitTestResult.from, expectedFrom ); - QCOMPARE( mMailClient->mUnitTestResult.to, expectedToList ); - QCOMPARE( mMailClient->mUnitTestResult.bcc, expectedBccList ); - QCOMPARE( mMailClient->mUnitTestResult.message->subject()->asUnicodeSt= ring(), expectedSubject ); + QCOMPARE( unitTestResult.from, expectedFrom ); + QCOMPARE( unitTestResult.to, expectedToList ); + QCOMPARE( unitTestResult.bcc, expectedBccList ); + QCOMPARE( unitTestResult.message->subject()->asUnicodeString(), expect= edSubject ); } = void testMailTo_data() @@ -310,9 +321,9 @@ private slots: = KCalCore::IncidenceBase::Ptr incidence( new KCalCore::Event() ); KPIMIdentities::Identity identity; - const QString from =3D QLatin1String( "from@kde.org" ); + const QString from =3D QLatin1String( s_ourEmail ); bool bccMe; - const QString recipients =3D QLatin1String( "Organizer " ); + const QString recipients =3D QLatin1String( "unittests@dev.nul" ); QString attachment; QString transport; MailClient::Result expectedResult =3D 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 " ); + toList << QLatin1String( s_ourEmail ); QStringList toBccList; //--------------------------------------------------------------------= -------------------------- QTest::newRow("test1") << incidence << identity << from << bccMe << re= cipients << attachment @@ -343,17 +354,19 @@ private slots: QFETCH( QString, expectedFrom ); QFETCH( QStringList, expectedToList ); QFETCH( QStringList, expectedBccList ); + mMailClient->sUnitTestResults.clear(); = mPendingSignals =3D 1; mMailClient->mailTo( incidence, identity, from, bccMe, recipients, att= achment, transport ); waitForSignals(); QCOMPARE( mLastResult, expectedResult ); + UnitTestResult unitTestResult =3D mMailClient->sUnitTestResults.first(= ); if ( expectedTransportId !=3D -1 ) - QCOMPARE( mMailClient->mUnitTestResult.transportId, expectedTranspor= tId ); + 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/t= ests/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=C3=A9rgio Martins + + 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 WI= THOUT + 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 Lice= nse + along with this library; see the file COPYING.LIB. If not, write to t= he + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Bosto= n, MA + 02110-1301, USA. +*/ + +#include "todopurgertest.h" + +#include "../etmcalendar.h" +#include "../todopurger.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace Akonadi; +using namespace KCalCore; + +Q_DECLARE_METATYPE( QSet ) + +void TodoPurgerTest::createTodo(const QString &uid, const QString &parentU= id, bool completed, bool recurring ) +{ + Item item; + item.setMimeType(Todo::todoMimeType()); + Todo::Ptr todo =3D Todo::Ptr(new Todo()); + todo->setUid(uid); + + const KDateTime today =3D KDateTime::currentDateTime(KDateTime::UTC); + const KDateTime yesterday =3D 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(todo); + ItemCreateJob *job =3D new ItemCreateJob(item, m_collection, this); + m_pendingCreations++; + AKVERIFYEXEC(job); +} + +void TodoPurgerTest::fetchCollection() +{ + CollectionFetchJob *job =3D new CollectionFetchJob(Collection::root(), + CollectionFetchJob::R= ecursive, + this); + // Get list of collections + job->fetchScope().setContentMimeTypes(QStringList() << QLatin1String("= application/x-vnd.akonadi.calendar.todo")); + AKVERIFYEXEC(job); + + // Find our collection + Collection::List collections =3D job->collections(); + QVERIFY(!collections.isEmpty()); + m_collection =3D collections.first(); + + QVERIFY(m_collection.isValid()); +} + +void TodoPurgerTest::initTestCase() +{ + AkonadiTest::checkTestIsIsolated(); + + qRegisterMetaType >("QSet"); + fetchCollection(); + + m_pendingCreations =3D 0; + m_pendingDeletions =3D 0; + m_calendar =3D new ETMCalendar(); + m_calendar->registerObserver(this); + m_todoPurger =3D new TodoPurger(this); + + connect(m_todoPurger, SIGNAL(todosPurged(bool,int,int)), SLOT(onTodosP= urged(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 =3D m_calendar->checkableProxyModel(); + const QModelIndex firstIndex =3D 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 =3D 8; + m_pendingPurgeSignal =3D 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 =3D=3D 0) { + QTestEventLoop::instance().exitLoop(); + } +} + +void TodoPurgerTest::calendarIncidenceDeleted(const Incidence::Ptr &) +{ + --m_pendingDeletions; + if (m_pendingDeletions =3D=3D 0 && !m_pendingPurgeSignal) { + QTestEventLoop::instance().exitLoop(); + } +} + +void TodoPurgerTest::onTodosPurged(bool success, int numDeleted, int numIg= nored) +{ + QVERIFY(success); + m_pendingPurgeSignal =3D false; + m_numDeleted =3D numDeleted; + m_numIgnored =3D numIgnored; + + if (m_pendingDeletions =3D=3D 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 (uncomplet= e 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 (uncomplet= e 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/tes= ts/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=C3=A9rgio Martins + + 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 WI= THOUT + 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 Lice= nse + along with this library; see the file COPYING.LIB. If not, write to t= he + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Bosto= n, MA + 02110-1301, USA. +*/ + +#ifndef TODOPURGER_TEST_H_ +#define TODOPURGER_TEST_H_ + +#include +#include +#include +#include + +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 &inciden= ce ); /**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 com= pleted, bool recurring =3D 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/tes= ts/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=C3=A9rgio Martins + + 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 WI= THOUT + 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 Lice= nse + along with this library; see the file COPYING.LIB. If not, write to t= he + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Bosto= n, MA + 02110-1301, USA. +*/ + + +#include "unittestbase.h" +#include "helper.h" +#include "../fetchjobcalendar.h" +#include "mailclient_p.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace Akonadi; +using namespace KCalCore; + +UnitTestBase::UnitTestBase() +{ + qRegisterMetaType("Akonadi::Item"); + qRegisterMetaType >("QLis= t"); + qRegisterMetaType >("QVector"); + qRegisterMetaType("Akonadi::MailClient::R= esult"); + + mChanger =3D new IncidenceChanger(this); + mChanger->setShowDialogsOnError(false); + mChanger->setHistoryEnabled(true); + + mCollection =3D 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 =3D generateIncidence(uid); + createIncidence(item); +} + +void UnitTestBase::createIncidence(const Item &item) +{ + QVERIFY(mCollection.isValid()); + ItemCreateJob *job =3D new ItemCreateJob(item, mCollection, this); + QVERIFY(job->exec()); +} + +void UnitTestBase::verifyExists(const QString &uid, bool exists) +{ + FetchJobCalendar *calendar =3D new FetchJobCalendar(); + connect(calendar, SIGNAL(loadFinished(bool,QString)), SLOT(onLoadFinis= hed(bool,QString))); + waitForIt(); + calendar->deleteLater(); + + QCOMPARE(calendar->incidence(uid) !=3D 0, exists); +} + +Akonadi::Item::List UnitTestBase::calendarItems() +{ + FetchJobCalendar::Ptr calendar =3D FetchJobCalendar::Ptr(new FetchJobC= alendar()); + connect(calendar.data(), SIGNAL(loadFinished(bool,QString)), SLOT(onLo= adFinished(bool,QString))); + waitForIt(); + KCalCore::ICalFormat format; + QString dump =3D format.toString(calendar.staticCast()); + qDebug() << dump; + calendar->deleteLater(); + return calendar->items(); +} + +void UnitTestBase::onLoadFinished(bool success, const QString &) +{ + QVERIFY(success); + stopWaiting(); +} + +void UnitTestBase::compareCalendars(const KCalCore::Calendar::Ptr &expecte= dCalendar) +{ + FetchJobCalendar::Ptr calendar =3D FetchJobCalendar::Ptr(new FetchJobC= alendar()); + connect(calendar.data(), SIGNAL(loadFinished(bool,QString)), SLOT(onLo= adFinished(bool,QString))); + waitForIt(); + + + // Now compare the expected calendar to the calendar we got. + Incidence::List incidences =3D calendar->incidences(); + Incidence::List expectedIncidences =3D expectedCalendar->incidences(); + + // First, replace the randomly generated UIDs with the UID that came i= n the invitation e-mail... + foreach (const KCalCore::Incidence::Ptr &incidence, incidences) { + incidence->setUid(incidence->schedulingID()); + qDebug() << "We have incidece with uid=3D" << incidence->uid() + << "; instanceidentifier=3D" << incidence->instanceIdenti= fier(); + foreach (const KCalCore::Attendee::Ptr &attendee, incidence->atten= dees()) { + 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=3D" << incidence->uid() + << "; instanceidentifier=3D" << incidence->instanceIdenti= fier(); + foreach (const KCalCore::Attendee::Ptr &attendee, incidence->atten= dees()) { + attendee->setUid(attendee->email()); + } + } + + QCOMPARE(incidences.count(), expectedIncidences.count()); + + foreach (const KCalCore::Incidence::Ptr &expectedIncidence, expectedIn= cidences) { + KCalCore::Incidence::Ptr incidence; + for (int i=3D0; iinstanceIdentifier() =3D=3D expectedInci= dence->instanceIdentifier()) { + incidence =3D 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 !=3D *incidence) { + ICalFormat format; + QString expectedData =3D format.toString(expectedIncidence); + QString gotData =3D format.toString(incidence); + qDebug() << "Test failed, expected:\n" << expectedData << "\nb= ut 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 &or= ganizer) +{ + Item item; + item.setMimeType(KCalCore::Event::eventMimeType()); + KCalCore::Incidence::Ptr incidence =3D KCalCore::Incidence::Ptr(new KC= alCore::Event()); + + if (!uid.isEmpty()) { + incidence->setUid(uid); + } + + const KDateTime now =3D KDateTime::currentUtcDateTime(); + incidence->setDtStart(now); + incidence->setDateTime(now.addSecs(3600), Incidence::RoleEnd); + incidence->setSummary(QLatin1String("summary")); + item.setPayload(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=C3=A9rgio Martins + + 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 WI= THOUT + 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 Lice= nse + along with this library; see the file COPYING.LIB. If not, write to t= he + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Bosto= n, MA + 02110-1301, USA. +*/ + + +#ifndef UNITTEST_BASE_H +#define UNITTEST_BASE_H + +#include +#include +#include + +#include +#include + +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 QStri= ng &organizer =3D QString()); + + Akonadi::Collection mCollection; + Akonadi::IncidenceChanger *mChanger; +}; + +#endif diff --git a/akonadi/calendar/tests/unittestenv/config-sqlite-db.xml b/akon= adi/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 @@ xdgconfig-sqlite.db xdglocal akonadi_ical_resource - akonadi_maildir_resource - akonadi_mailtransport_dummy_resource true sqlite diff --git a/akonadi/calendar/tests/unittestenv/kdehome/share/config/akonad= i_maildir_resource_0rc b/akonadi/calendar/tests/unittestenv/kdehome/share/c= onfig/akonadi_maildir_resource_0rc deleted file mode 100644 index 2488d2d..0000000 --- a/akonadi/calendar/tests/unittestenv/kdehome/share/config/akonadi_maild= ir_resource_0rc +++ /dev/null @@ -1,2 +0,0 @@ -[General] -Path[$e]=3D$HOME/.local/share/local-mail diff --git a/akonadi/calendar/tests/unittestenv/kdehome/share/config/akonad= i_mailtransport_dummy_resource_0rc b/akonadi/calendar/tests/unittestenv/kde= home/share/config/akonadi_mailtransport_dummy_resource_0rc deleted file mode 100644 index eddc6c7..0000000 --- a/akonadi/calendar/tests/unittestenv/kdehome/share/config/akonadi_mailt= ransport_dummy_resource_0rc +++ /dev/null @@ -1,2 +0,0 @@ -[General] -Sink=3D4 diff --git a/akonadi/calendar/tests/unittestenv/kdehome/share/config/kdebug= rc 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=3Dfalse + +[1000] +InfoOutput=3D2 + +[10000] +InfoOutput=3D2 + +[100000] +InfoOutput=3D2 + +[100001] +InfoOutput=3D2 + +[100100] +InfoOutput=3D2 + +[100101] +InfoOutput=3D2 + +[100200] +InfoOutput=3D2 + +[10500] +InfoOutput=3D2 + +[1100] +InfoOutput=3D2 + +[11000] +InfoOutput=3D2 + +[11002] +InfoOutput=3D2 + +[11003] +InfoOutput=3D2 + +[11004] +InfoOutput=3D2 + +[11005] +InfoOutput=3D2 + +[12000] +InfoOutput=3D2 + +[12001] +InfoOutput=3D2 + +[12002] +InfoOutput=3D2 + +[12003] +InfoOutput=3D2 + +[12004] +InfoOutput=3D2 + +[12005] +InfoOutput=3D2 + +[12006] +InfoOutput=3D2 + +[12007] +InfoOutput=3D2 + +[12008] +InfoOutput=3D2 + +[12009] +InfoOutput=3D2 + +[1201] +InfoOutput=3D2 + +[12010] +InfoOutput=3D2 + +[12011] +InfoOutput=3D2 + +[12012] +InfoOutput=3D2 + +[1203] +InfoOutput=3D2 + +[1204] +InfoOutput=3D2 + +[1205] +InfoOutput=3D2 + +[1206] +InfoOutput=3D2 + +[1207] +InfoOutput=3D2 + +[1208] +InfoOutput=3D2 + +[1209] +InfoOutput=3D2 + +[1211] +InfoOutput=3D2 + +[1212] +InfoOutput=3D2 + +[1215] +InfoOutput=3D2 + +[1216] +InfoOutput=3D2 + +[1218] +InfoOutput=3D2 + +[1220] +InfoOutput=3D2 + +[1221] +InfoOutput=3D2 + +[1222] +InfoOutput=3D2 + +[13000] +InfoOutput=3D2 + +[13001] +InfoOutput=3D2 + +[13002] +InfoOutput=3D2 + +[13010] +InfoOutput=3D2 + +[13020] +InfoOutput=3D2 + +[13025] +InfoOutput=3D2 + +[13030] +InfoOutput=3D2 + +[13033] +InfoOutput=3D2 + +[13035] +InfoOutput=3D2 + +[13040] +InfoOutput=3D2 + +[13050] +InfoOutput=3D2 + +[13051] +InfoOutput=3D2 + +[13060] +InfoOutput=3D2 + +[13070] +InfoOutput=3D2 + +[1400] +InfoOutput=3D2 + +[14000] +InfoOutput=3D2 + +[14001] +InfoOutput=3D2 + +[1401] +InfoOutput=3D2 + +[14010] +InfoOutput=3D2 + +[1402] +InfoOutput=3D2 + +[1410] +InfoOutput=3D2 + +[14100] +InfoOutput=3D2 + +[14101] +InfoOutput=3D2 + +[14110] +InfoOutput=3D2 + +[14111] +InfoOutput=3D2 + +[14120] +InfoOutput=3D2 + +[14121] +InfoOutput=3D2 + +[14130] +InfoOutput=3D2 + +[14131] +InfoOutput=3D2 + +[14140] +InfoOutput=3D2 + +[14141] +InfoOutput=3D2 + +[14150] +InfoOutput=3D2 + +[14151] +InfoOutput=3D2 + +[14152] +InfoOutput=3D2 + +[14153] +InfoOutput=3D2 + +[14160] +InfoOutput=3D2 + +[14161] +InfoOutput=3D2 + +[14170] +InfoOutput=3D2 + +[14171] +InfoOutput=3D2 + +[14180] +InfoOutput=3D2 + +[14181] +InfoOutput=3D2 + +[14190] +InfoOutput=3D2 + +[14191] +InfoOutput=3D2 + +[14192] +InfoOutput=3D2 + +[1420] +InfoOutput=3D2 + +[14200] +InfoOutput=3D2 + +[1421] +InfoOutput=3D2 + +[14210] +InfoOutput=3D2 + +[14220] +InfoOutput=3D2 + +[1430] +InfoOutput=3D2 + +[14300] +InfoOutput=3D2 + +[14301] +InfoOutput=3D2 + +[14302] +InfoOutput=3D2 + +[14303] +InfoOutput=3D2 + +[14304] +InfoOutput=3D2 + +[14305] +InfoOutput=3D2 + +[14306] +InfoOutput=3D2 + +[14307] +InfoOutput=3D2 + +[14308] +InfoOutput=3D2 + +[14309] +InfoOutput=3D2 + +[1431] +InfoOutput=3D2 + +[14310] +InfoOutput=3D2 + +[14311] +InfoOutput=3D2 + +[14312] +InfoOutput=3D2 + +[14313] +InfoOutput=3D2 + +[14314] +InfoOutput=3D2 + +[14315] +InfoOutput=3D2 + +[14316] +InfoOutput=3D2 + +[14317] +InfoOutput=3D2 + +[14318] +InfoOutput=3D2 + +[1432] +InfoOutput=3D2 + +[1433] +InfoOutput=3D2 + +[1440] +InfoOutput=3D2 + +[14400] +InfoOutput=3D2 + +[1441] +InfoOutput=3D2 + +[15000] +InfoOutput=3D2 + +[1511] +InfoOutput=3D2 + +[1512] +InfoOutput=3D2 + +[1601] +InfoOutput=3D2 + +[161] +InfoOutput=3D2 + +[170] +InfoOutput=3D2 + +[174] +InfoOutput=3D2 + +[175] +InfoOutput=3D2 + +[176] +InfoOutput=3D2 + +[179] +InfoOutput=3D2 + +[180] +InfoOutput=3D2 + +[1800] +InfoOutput=3D2 + +[1801] +InfoOutput=3D2 + +[1802] +InfoOutput=3D2 + +[1803] +InfoOutput=3D2 + +[1804] +InfoOutput=3D2 + +[1805] +InfoOutput=3D2 + +[1806] +InfoOutput=3D2 + +[1901] +InfoOutput=3D2 + +[1902] +InfoOutput=3D2 + +[1903] +InfoOutput=3D2 + +[2000] +InfoOutput=3D2 + +[20000] +InfoOutput=3D2 + +[200000] +InfoOutput=3D2 + +[200001] +InfoOutput=3D2 + +[200002] +InfoOutput=3D2 + +[200003] +InfoOutput=3D2 + +[200004] +InfoOutput=3D2 + +[20001] +InfoOutput=3D2 + +[2001] +InfoOutput=3D2 + +[20010] +InfoOutput=3D2 + +[20011] +InfoOutput=3D2 + +[20012] +InfoOutput=3D2 + +[2002] +InfoOutput=3D2 + +[2003] +InfoOutput=3D2 + +[2100] +InfoOutput=3D2 + +[2200] +InfoOutput=3D2 + +[23000] +InfoOutput=3D2 + +[23100] +InfoOutput=3D2 + +[240] +InfoOutput=3D2 + +[2400] +InfoOutput=3D2 + +[24000] +InfoOutput=3D2 + +[24001] +InfoOutput=3D2 + +[24002] +InfoOutput=3D2 + +[2401] +InfoOutput=3D2 + +[2402] +InfoOutput=3D2 + +[2403] +InfoOutput=3D2 + +[2404] +InfoOutput=3D2 + +[2405] +InfoOutput=3D2 + +[260] +InfoOutput=3D2 + +[265] +InfoOutput=3D2 + +[26500] +InfoOutput=3D2 + +[26550] +InfoOutput=3D2 + +[26560] +InfoOutput=3D2 + +[26600] +InfoOutput=3D2 + +[26650] +InfoOutput=3D2 + +[28000] +InfoOutput=3D2 + +[281] +InfoOutput=3D2 + +[282] +InfoOutput=3D2 + +[283] +InfoOutput=3D2 + +[285] +InfoOutput=3D2 + +[29000] +InfoOutput=3D2 + +[291] +InfoOutput=3D2 + +[292] +InfoOutput=3D2 + +[293] +InfoOutput=3D2 + +[297] +InfoOutput=3D2 + +[299] +InfoOutput=3D2 + +[3000] +InfoOutput=3D2 + +[300000] +InfoOutput=3D2 + +[300001] +InfoOutput=3D2 + +[300100] +InfoOutput=3D2 + +[300101] +InfoOutput=3D2 + +[300102] +InfoOutput=3D2 + +[300103] +InfoOutput=3D2 + +[300104] +InfoOutput=3D2 + +[300105] +InfoOutput=3D2 + +[300106] +InfoOutput=3D2 + +[300200] +InfoOutput=3D2 + +[30501] +InfoOutput=3D2 + +[30502] +InfoOutput=3D2 + +[30503] +InfoOutput=3D2 + +[30504] +InfoOutput=3D2 + +[30505] +InfoOutput=3D2 + +[30506] +InfoOutput=3D2 + +[30507] +InfoOutput=3D2 + +[30508] +InfoOutput=3D2 + +[30509] +InfoOutput=3D2 + +[30510] +InfoOutput=3D2 + +[30511] +InfoOutput=3D2 + +[30512] +InfoOutput=3D2 + +[30513] +InfoOutput=3D2 + +[30514] +InfoOutput=3D2 + +[30515] +InfoOutput=3D2 + +[30516] +InfoOutput=3D2 + +[30517] +InfoOutput=3D2 + +[30518] +InfoOutput=3D2 + +[30519] +InfoOutput=3D2 + +[30520] +InfoOutput=3D2 + +[30521] +InfoOutput=3D2 + +[30522] +InfoOutput=3D2 + +[30523] +InfoOutput=3D2 + +[30525] +InfoOutput=3D2 + +[3100] +InfoOutput=3D2 + +[32500] +InfoOutput=3D2 + +[32600] +InfoOutput=3D2 + +[34001] +InfoOutput=3D2 + +[35000] +InfoOutput=3D2 + +[38000] +InfoOutput=3D2 + +[399] +InfoOutput=3D2 + +[410] +InfoOutput=3D2 + +[4300] +InfoOutput=3D2 + +[4400] +InfoOutput=3D2 + +[44000] +InfoOutput=3D2 + +[44001] +InfoOutput=3D2 + +[44010] +InfoOutput=3D2 + +[44019] +InfoOutput=3D2 + +[44020] +InfoOutput=3D2 + +[44021] +InfoOutput=3D2 + +[44022] +InfoOutput=3D2 + +[44023] +InfoOutput=3D2 + +[44024] +InfoOutput=3D2 + +[4500] +InfoOutput=3D2 + +[4600] +InfoOutput=3D2 + +[4610] +InfoOutput=3D2 + +[4620] +InfoOutput=3D2 + +[4630] +InfoOutput=3D2 + +[4640] +InfoOutput=3D2 + +[4700] +InfoOutput=3D2 + +[4710] +InfoOutput=3D2 + +[4711] +InfoOutput=3D2 + +[4712] +InfoOutput=3D2 + +[4713] +InfoOutput=3D2 + +[4714] +InfoOutput=3D2 + +[4715] +InfoOutput=3D2 + +[500] +InfoOutput=3D2 + +[50001] +InfoOutput=3D2 + +[50003] +InfoOutput=3D2 + +[50004] +InfoOutput=3D2 + +[50005] +InfoOutput=3D2 + +[50006] +InfoOutput=3D2 + +[50007] +InfoOutput=3D2 + +[5001] +InfoOutput=3D2 + +[5002] +InfoOutput=3D2 + +[5003] +InfoOutput=3D2 + +[5005] +InfoOutput=3D2 + +[5007] +InfoOutput=3D2 + +[5009] +InfoOutput=3D2 + +[5010] +InfoOutput=3D2 + +[5011] +InfoOutput=3D2 + +[5012] +InfoOutput=3D2 + +[5050] +InfoOutput=3D2 + +[5051] +InfoOutput=3D2 + +[5052] +InfoOutput=3D2 + +[5100] +InfoOutput=3D2 + +[51000] +InfoOutput=3D2 + +[51001] +InfoOutput=3D2 + +[51002] +InfoOutput=3D2 + +[51003] +InfoOutput=3D2 + +[51004] +InfoOutput=3D2 + +[51005] +InfoOutput=3D2 + +[51006] +InfoOutput=3D2 + +[51007] +InfoOutput=3D2 + +[51010] +InfoOutput=3D2 + +[51011] +InfoOutput=3D2 + +[51012] +InfoOutput=3D2 + +[51013] +InfoOutput=3D2 + +[51014] +InfoOutput=3D2 + +[51020] +InfoOutput=3D2 + +[5149] +InfoOutput=3D2 + +[5150] +InfoOutput=3D2 + +[5151] +InfoOutput=3D2 + +[5152] +InfoOutput=3D2 + +[5153] +InfoOutput=3D2 + +[5154] +InfoOutput=3D2 + +[5200] +InfoOutput=3D2 + +[5250] +InfoOutput=3D2 + +[5251] +InfoOutput=3D2 + +[5252] +InfoOutput=3D2 + +[5253] +InfoOutput=3D2 + +[5254] +InfoOutput=3D2 + +[5255] +InfoOutput=3D2 + +[5256] +InfoOutput=3D2 + +[5257] +InfoOutput=3D2 + +[5258] +InfoOutput=3D2 + +[5259] +InfoOutput=3D2 + +[5260] +InfoOutput=3D2 + +[5261] +InfoOutput=3D2 + +[5262] +InfoOutput=3D2 + +[5263] +InfoOutput=3D2 + +[5264] +InfoOutput=3D2 + +[5265] +InfoOutput=3D2 + +[5266] +InfoOutput=3D2 + +[5295] +InfoOutput=3D2 + +[5300] +InfoOutput=3D2 + +[5310] +InfoOutput=3D2 + +[5320] +InfoOutput=3D2 + +[5321] +InfoOutput=3D2 + +[5322] +InfoOutput=3D2 + +[5323] +InfoOutput=3D2 + +[5324] +InfoOutput=3D2 + +[5325] +InfoOutput=3D2 + +[5326] +InfoOutput=3D2 + +[5327] +InfoOutput=3D2 + +[5328] +InfoOutput=3D2 + +[5329] +InfoOutput=3D2 + +[5350] +InfoOutput=3D2 + +[550] +InfoOutput=3D2 + +[5500] +InfoOutput=3D2 + +[551] +InfoOutput=3D2 + +[5510] +InfoOutput=3D2 + +[5511] +InfoOutput=3D2 + +[5512] +InfoOutput=3D2 + +[5600] +InfoOutput=3D2 + +[5601] +InfoOutput=3D2 + +[5602] +InfoOutput=3D2 + +[5650] +InfoOutput=3D2 + +[5700] +InfoOutput=3D2 + +[5720] +InfoOutput=3D2 + +[5800] +InfoOutput=3D2 + +[5810] +InfoOutput=3D2 + +[5820] +InfoOutput=3D2 + +[5850] +InfoOutput=3D2 + +[5860] +InfoOutput=3D2 + +[5890] +InfoOutput=3D2 + +[5900] +InfoOutput=3D2 + +[5950] +InfoOutput=3D2 + +[5951] +InfoOutput=3D2 + +[5952] +InfoOutput=3D2 + +[5953] +InfoOutput=3D2 + +[5954] +InfoOutput=3D2 + +[5955] +InfoOutput=3D2 + +[5960] +InfoOutput=3D2 + +[5970] +InfoOutput=3D2 + +[5975] +InfoOutput=3D2 + +[600] +InfoOutput=3D2 + +[6000] +InfoOutput=3D2 + +[60001] +InfoOutput=3D2 + +[60002] +InfoOutput=3D2 + +[60005] +InfoOutput=3D2 + +[60010] +InfoOutput=3D2 + +[6005] +InfoOutput=3D2 + +[601] +InfoOutput=3D2 + +[6010] +InfoOutput=3D2 + +[6011] +InfoOutput=3D2 + +[6020] +InfoOutput=3D2 + +[6030] +InfoOutput=3D2 + +[6031] +InfoOutput=3D2 + +[6035] +InfoOutput=3D2 + +[6036] +InfoOutput=3D2 + +[6040] +InfoOutput=3D2 + +[6041] +InfoOutput=3D2 + +[6045] +InfoOutput=3D2 + +[6050] +InfoOutput=3D2 + +[6060] +InfoOutput=3D2 + +[6061] +InfoOutput=3D2 + +[6070] +InfoOutput=3D2 + +[6080] +InfoOutput=3D2 + +[6090] +InfoOutput=3D2 + +[6100] +InfoOutput=3D2 + +[6200] +InfoOutput=3D2 + +[6201] +InfoOutput=3D2 + +[6210] +InfoOutput=3D2 + +[65432] +InfoOutput=3D2 + +[66666] +InfoOutput=3D2 + +[67000] +InfoOutput=3D2 + +[67100] +InfoOutput=3D2 + +[67200] +InfoOutput=3D2 + +[700] +InfoOutput=3D2 + +[7000] +InfoOutput=3D2 + +[7002] +InfoOutput=3D2 + +[7003] +InfoOutput=3D2 + +[7004] +InfoOutput=3D2 + +[7005] +InfoOutput=3D2 + +[7006] +InfoOutput=3D2 + +[7007] +InfoOutput=3D2 + +[7008] +InfoOutput=3D2 + +[701] +InfoOutput=3D2 + +[7011] +InfoOutput=3D2 + +[7014] +InfoOutput=3D2 + +[7015] +InfoOutput=3D2 + +[7016] +InfoOutput=3D2 + +[7017] +InfoOutput=3D2 + +[7019] +InfoOutput=3D2 + +[702] +InfoOutput=3D2 + +[7020] +InfoOutput=3D2 + +[7021] +InfoOutput=3D2 + +[7022] +InfoOutput=3D2 + +[7023] +InfoOutput=3D2 + +[7024] +InfoOutput=3D2 + +[7025] +InfoOutput=3D2 + +[7027] +InfoOutput=3D2 + +[7028] +InfoOutput=3D2 + +[7029] +InfoOutput=3D2 + +[7030] +InfoOutput=3D2 + +[7031] +InfoOutput=3D2 + +[7032] +InfoOutput=3D2 + +[7033] +InfoOutput=3D2 + +[7034] +InfoOutput=3D2 + +[704] +InfoOutput=3D2 + +[7040] +InfoOutput=3D2 + +[7041] +InfoOutput=3D2 + +[7042] +InfoOutput=3D2 + +[7043] +InfoOutput=3D2 + +[7044] +InfoOutput=3D2 + +[710] +InfoOutput=3D2 + +[7101] +InfoOutput=3D2 + +[7102] +InfoOutput=3D2 + +[7103] +InfoOutput=3D2 + +[7104] +InfoOutput=3D2 + +[7105] +InfoOutput=3D2 + +[7106] +InfoOutput=3D2 + +[7107] +InfoOutput=3D2 + +[7108] +InfoOutput=3D2 + +[7109] +InfoOutput=3D2 + +[711] +InfoOutput=3D2 + +[7110] +InfoOutput=3D2 + +[7111] +InfoOutput=3D2 + +[7112] +InfoOutput=3D2 + +[7115] +InfoOutput=3D2 + +[7116] +InfoOutput=3D2 + +[7117] +InfoOutput=3D2 + +[7119] +InfoOutput=3D2 + +[712] +InfoOutput=3D2 + +[7120] +InfoOutput=3D2 + +[7121] +InfoOutput=3D2 + +[7122] +InfoOutput=3D2 + +[7123] +InfoOutput=3D2 + +[7124] +InfoOutput=3D2 + +[7125] +InfoOutput=3D2 + +[7126] +InfoOutput=3D2 + +[7127] +InfoOutput=3D2 + +[7128] +InfoOutput=3D2 + +[7129] +InfoOutput=3D2 + +[713] +InfoOutput=3D2 + +[7131] +InfoOutput=3D2 + +[800] +InfoOutput=3D2 + +[80001] +InfoOutput=3D2 + +[8050] +InfoOutput=3D2 + +[8051] +InfoOutput=3D2 + +[8060] +InfoOutput=3D2 + +[8100] +InfoOutput=3D2 + +[8101] +InfoOutput=3D2 + +[8102] +InfoOutput=3D2 + +[8103] +InfoOutput=3D2 + +[8104] +InfoOutput=3D2 + +[8105] +InfoOutput=3D2 + +[8106] +InfoOutput=3D2 + +[8110] +InfoOutput=3D2 + +[8111] +InfoOutput=3D2 + +[8112] +InfoOutput=3D2 + +[8113] +InfoOutput=3D2 + +[9000] +InfoOutput=3D2 + +[90000] +InfoOutput=3D2 + +[9001] +InfoOutput=3D2 + +[90010] +InfoOutput=3D2 + +[9002] +InfoOutput=3D2 + +[90020] +InfoOutput=3D2 + +[9003] +InfoOutput=3D2 + +[9004] +InfoOutput=3D2 + +[9007] +InfoOutput=3D2 + +[9010] +InfoOutput=3D2 + +[90100] +InfoOutput=3D2 + +[9011] +InfoOutput=3D2 + +[90110] +InfoOutput=3D2 + +[9012] +InfoOutput=3D2 + +[90120] +InfoOutput=3D2 + +[9013] +InfoOutput=3D2 + +[90130] +InfoOutput=3D2 + +[90150] +InfoOutput=3D2 + +[90160] +InfoOutput=3D2 + +[9017] +InfoOutput=3D2 + +[90170] +InfoOutput=3D2 + +[90180] +InfoOutput=3D2 + +[90190] +InfoOutput=3D2 + +[90210] +InfoOutput=3D2 + +[9024] +InfoOutput=3D2 + +[9025] +InfoOutput=3D2 + +[9032] +InfoOutput=3D2 + +[9035] +InfoOutput=3D2 + +[9037] +InfoOutput=3D2 + +[9038] +InfoOutput=3D2 + +[9039] +InfoOutput=3D2 + +[9040] +InfoOutput=3D2 + +[9041] +InfoOutput=3D2 + +[9042] +InfoOutput=3D2 + +[9043] +InfoOutput=3D2 + +[9044] +InfoOutput=3D2 + +[9045] +InfoOutput=3D2 + +[9046] +InfoOutput=3D2 + +[912] +InfoOutput=3D2 + +[920] +InfoOutput=3D2 + +[921] +InfoOutput=3D2 + +[930] +InfoOutput=3D2 + +[9500] +InfoOutput=3D2 + +[9501] +InfoOutput=3D2 + +[9502] +InfoOutput=3D2 + +[9503] +InfoOutput=3D2 + +[9504] +InfoOutput=3D2 + +[9505] +InfoOutput=3D2 + +[9506] +InfoOutput=3D2 + +[9507] +InfoOutput=3D2 + +[9508] +InfoOutput=3D2 + +[9509] +InfoOutput=3D2 + +[9510] +InfoOutput=3D2 + +[9511] +InfoOutput=3D2 + +[9512] +InfoOutput=3D2 + +[9513] +InfoOutput=3D2 + +[9514] +InfoOutput=3D2 + +[9515] +InfoOutput=3D2 + +[9516] +InfoOutput=3D2 + +[9517] +InfoOutput=3D2 + +[9518] +InfoOutput=3D2 + +[9519] +InfoOutput=3D2 + +[9520] +InfoOutput=3D2 + +[9521] +InfoOutput=3D2 + +[9522] +InfoOutput=3D2 + +[9523] +InfoOutput=3D2 + +[9524] +InfoOutput=3D2 + +[9525] +InfoOutput=3D2 + +[9526] +InfoOutput=3D2 + +[9527] +InfoOutput=3D2 + +[9528] +InfoOutput=3D2 + +[9529] +InfoOutput=3D2 + +[9530] +InfoOutput=3D2 + +[9531] +InfoOutput=3D2 + +[9532] +InfoOutput=3D2 + +[AkonadiAgentServer] +InfoOutput=3D2 + +[KSharedDataCache] +InfoOutput=3D4 + +[Oxygen ( style )] +InfoOutput=3D2 + +[akonadi_archivemail_agent] +InfoOutput=3D2 + +[akonadi_folderarchive_agent] +InfoOutput=3D2 + +[akonadi_maildispatcher_agent] +InfoOutput=3D2 + +[akonadi_mailfilter_agent] +InfoOutput=3D2 + +[akonadi_migration_agent] +InfoOutput=3D2 + +[akonadi_nepomuk_feeder] +InfoOutput=3D2 + +[akonadiconsole] +InfoOutput=3D2 + +[kbuildsycoca4] +InfoOutput=3D2 + +[kdecore (KConfigSkeleton)] +InfoOutput=3D2 + +[unnamed app] +InfoOutput=3D2