File indexing completed on 2024-05-12 05:10:37

0001 /*
0002     SPDX-FileCopyrightText: 2011-2013 Sérgio Martins <iamsergio@gmail.com>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "etmcalendartest.h"
0008 
0009 #include "../src/etmcalendar.h"
0010 #include <Akonadi/CalendarUtils>
0011 #include <Akonadi/CollectionFetchJob>
0012 #include <Akonadi/CollectionFetchScope>
0013 #include <Akonadi/CollectionModifyJob>
0014 #include <Akonadi/ItemCreateJob>
0015 #include <Akonadi/ItemDeleteJob>
0016 #include <Akonadi/ItemModifyJob>
0017 #include <KCheckableProxyModel>
0018 #include <KEMailSettings>
0019 #include <akonadi/qtest_akonadi.h>
0020 
0021 #include <QSignalSpy>
0022 #include <QTestEventLoop>
0023 
0024 using namespace Akonadi;
0025 using namespace KCalendarCore;
0026 
0027 Q_DECLARE_METATYPE(QSet<QByteArray>)
0028 
0029 void ETMCalendarTest::createIncidence(const QString &uid)
0030 {
0031     Item item;
0032     item.setMimeType(Event::eventMimeType());
0033     Incidence::Ptr incidence = Incidence::Ptr(new Event());
0034     incidence->setUid(uid);
0035     incidence->setDtStart(QDateTime::currentDateTimeUtc());
0036     incidence->setSummary(QStringLiteral("summary"));
0037     item.setPayload<KCalendarCore::Incidence::Ptr>(incidence);
0038     auto job = new ItemCreateJob(item, mCollection, this);
0039     AKVERIFYEXEC(job);
0040 }
0041 
0042 void ETMCalendarTest::createTodo(const QString &uid, const QString &parentUid)
0043 {
0044     Item item;
0045     item.setMimeType(Todo::todoMimeType());
0046     Todo::Ptr todo = Todo::Ptr(new Todo());
0047     todo->setUid(uid);
0048 
0049     todo->setRelatedTo(parentUid);
0050 
0051     todo->setSummary(QStringLiteral("summary"));
0052 
0053     item.setPayload<KCalendarCore::Incidence::Ptr>(todo);
0054     auto job = new ItemCreateJob(item, mCollection, this);
0055     mIncidencesToAdd++;
0056     mIncidencesToChange++;
0057     AKVERIFYEXEC(job);
0058 }
0059 
0060 void ETMCalendarTest::deleteIncidence(const QString &uid)
0061 {
0062     auto job = new ItemDeleteJob(mCalendar->item(uid));
0063     mIncidencesToDelete++;
0064     AKVERIFYEXEC(job);
0065 }
0066 
0067 void ETMCalendarTest::fetchCollection()
0068 {
0069     auto job = new CollectionFetchJob(Collection::root(), CollectionFetchJob::Recursive, this);
0070     // Get list of collections
0071     job->fetchScope().setContentMimeTypes(QStringList() << QStringLiteral("application/x-vnd.akonadi.calendar.event"));
0072     AKVERIFYEXEC(job);
0073 
0074     // Find our collection
0075     Collection::List collections = job->collections();
0076     QVERIFY(!collections.isEmpty());
0077     mCollection = collections.first();
0078 
0079     QVERIFY(mCollection.isValid());
0080 }
0081 
0082 void ETMCalendarTest::initTestCase()
0083 {
0084     AkonadiTest::checkTestIsIsolated();
0085     mIncidencesToAdd = 0;
0086     mIncidencesToChange = 0;
0087     mIncidencesToDelete = 0;
0088 
0089     qRegisterMetaType<QSet<QByteArray>>("QSet<QByteArray>");
0090     fetchCollection();
0091 
0092     mCalendar = new ETMCalendar();
0093     QVERIFY(mCalendar->isLoading());
0094     connect(mCalendar, &ETMCalendar::collectionsAdded, this, &ETMCalendarTest::handleCollectionsAdded);
0095 
0096     mCalendar->registerObserver(this);
0097 
0098     // Wait for the collection
0099     QTestEventLoop::instance().enterLoop(10);
0100     QVERIFY(!QTestEventLoop::instance().timeout());
0101 
0102     KCheckableProxyModel *checkable = mCalendar->checkableProxyModel();
0103     const QModelIndex firstIndex = checkable->index(0, 0);
0104     QVERIFY(firstIndex.isValid());
0105     checkable->setData(firstIndex, Qt::Checked, Qt::CheckStateRole);
0106 
0107     mIncidencesToAdd = 6;
0108     createIncidence(tr("a"));
0109     createIncidence(tr("b"));
0110     createIncidence(tr("c"));
0111     createIncidence(tr("d"));
0112     createIncidence(tr("e"));
0113     createIncidence(tr("f"));
0114 
0115     // Wait for incidences
0116     QTestEventLoop::instance().enterLoop(10);
0117     QVERIFY(!QTestEventLoop::instance().timeout());
0118     QVERIFY(!mCalendar->isLoading());
0119 }
0120 
0121 void ETMCalendarTest::cleanupTestCase()
0122 {
0123     delete mCalendar;
0124 }
0125 
0126 void ETMCalendarTest::testCollectionChanged_data()
0127 {
0128     QTest::addColumn<Akonadi::Collection>("noRightsCollection");
0129     Collection noRightsCollection = mCollection;
0130     noRightsCollection.setRights(Collection::Rights(Collection::CanCreateItem));
0131     QTest::newRow("change rights") << noRightsCollection;
0132 }
0133 
0134 void ETMCalendarTest::testCollectionChanged()
0135 {
0136     QFETCH(Akonadi::Collection, noRightsCollection);
0137     auto job = new CollectionModifyJob(mCollection, this);
0138     QSignalSpy spy(mCalendar, &ETMCalendar::collectionChanged);
0139     mIncidencesToChange = 6;
0140     AKVERIFYEXEC(job);
0141     QTestEventLoop::instance().enterLoop(10);
0142     QVERIFY(!QTestEventLoop::instance().timeout());
0143     QCOMPARE(spy.count(), 1);
0144     QCOMPARE(spy.at(0).count(), 2);
0145     QCOMPARE(spy.at(0).at(0).value<Akonadi::Collection>(), mCollection);
0146     QVERIFY(spy.at(0).at(1).value<QSet<QByteArray>>().contains(QByteArray("AccessRights")));
0147 }
0148 
0149 void ETMCalendarTest::testIncidencesAdded()
0150 {
0151     // Already tested above.
0152 }
0153 
0154 void ETMCalendarTest::testIncidencesModified()
0155 {
0156     const QString uid = tr("d");
0157     Item item = mCalendar->item(uid);
0158     QVERIFY(item.isValid());
0159     QVERIFY(item.hasPayload());
0160     Incidence::Ptr clone = Incidence::Ptr(CalendarUtils::incidence(item)->clone());
0161     clone->setSummary(tr("foo33"));
0162     item.setPayload(clone);
0163     auto job = new ItemModifyJob(item);
0164     mIncidencesToChange = 1;
0165     AKVERIFYEXEC(job);
0166     QTestEventLoop::instance().enterLoop(10);
0167     QVERIFY(!QTestEventLoop::instance().timeout());
0168     QCOMPARE(mCalendar->incidence(uid)->summary(), tr("foo33"));
0169     QVERIFY(item.revision() == mCalendar->item(item.id()).revision() - 1);
0170 }
0171 
0172 void ETMCalendarTest::testIncidencesDeleted()
0173 {
0174     Event::List incidences = mCalendar->events();
0175     QCOMPARE(incidences.count(), 6);
0176     const Item item = mCalendar->item(tr("a"));
0177     QVERIFY(item.isValid());
0178     QVERIFY(item.hasPayload());
0179     auto job = new ItemDeleteJob(item);
0180     AKVERIFYEXEC(job);
0181     mIncidencesToDelete = 1;
0182     QTestEventLoop::instance().enterLoop(10);
0183     QVERIFY(!QTestEventLoop::instance().timeout());
0184     QCOMPARE(mLastDeletedUid, tr("a"));
0185     QVERIFY(!mCalendar->item(tr("a")).isValid());
0186 }
0187 
0188 void ETMCalendarTest::testFilteredModel()
0189 {
0190     QVERIFY(mCalendar->model());
0191 }
0192 
0193 void ETMCalendarTest::testUnfilteredModel()
0194 {
0195     QVERIFY(mCalendar->entityTreeModel());
0196 }
0197 
0198 void ETMCalendarTest::testCheckableProxyModel()
0199 {
0200     QVERIFY(mCalendar->checkableProxyModel());
0201 }
0202 
0203 void ETMCalendarTest::testUnselectCollection()
0204 {
0205     mIncidencesToAdd = mIncidencesToDelete = mCalendar->incidences().count();
0206     const int originalToDelete = mIncidencesToDelete;
0207     KCheckableProxyModel *checkable = mCalendar->checkableProxyModel();
0208     const QModelIndex firstIndex = checkable->index(0, 0);
0209     QVERIFY(firstIndex.isValid());
0210     checkable->setData(firstIndex, Qt::Unchecked, Qt::CheckStateRole);
0211 
0212     if (mIncidencesToDelete > 0) { // Actually they probably where deleted already
0213         // doesn't need the event loop, but just in case
0214         QTestEventLoop::instance().enterLoop(10);
0215 
0216         if (QTestEventLoop::instance().timeout()) {
0217             qDebug() << originalToDelete << mIncidencesToDelete;
0218             QVERIFY(false);
0219         }
0220     }
0221 }
0222 
0223 void ETMCalendarTest::testSelectCollection()
0224 {
0225     KCheckableProxyModel *checkable = mCalendar->checkableProxyModel();
0226     const QModelIndex firstIndex = checkable->index(0, 0);
0227     QVERIFY(firstIndex.isValid());
0228     checkable->setData(firstIndex, Qt::Checked, Qt::CheckStateRole);
0229 
0230     if (mIncidencesToDelete > 0) {
0231         QTestEventLoop::instance().enterLoop(10);
0232         QVERIFY(!QTestEventLoop::instance().timeout());
0233     }
0234 }
0235 
0236 void ETMCalendarTest::calendarIncidenceAdded(const Incidence::Ptr &incidence)
0237 {
0238     Q_ASSERT(incidence);
0239 
0240     const QString id = incidence->customProperty("VOLATILE", "AKONADI-ID");
0241     QCOMPARE(id.toLongLong(), mCalendar->item(incidence->uid()).id());
0242 
0243     QVERIFY(mIncidencesToAdd > 0);
0244     --mIncidencesToAdd;
0245     checkExitLoop();
0246 }
0247 
0248 void ETMCalendarTest::handleCollectionsAdded(const Akonadi::Collection::List &)
0249 {
0250     QVERIFY(mCalendar->isLoading());
0251     QTestEventLoop::instance().exitLoop();
0252 }
0253 
0254 void ETMCalendarTest::calendarIncidenceChanged(const Incidence::Ptr &incidence)
0255 {
0256     const QString id = incidence->customProperty("VOLATILE", "AKONADI-ID");
0257 
0258     Akonadi::Item item = mCalendar->item(incidence->uid());
0259     QVERIFY(item.isValid());
0260     QVERIFY(item.hasPayload());
0261     Incidence::Ptr i2 = CalendarUtils::incidence(item);
0262 
0263     if (id.toLongLong() != item.id()) {
0264         qDebug() << "Incidence uid = " << incidence->uid() << "; internal incidence uid = " << i2->uid();
0265         QVERIFY(false);
0266     }
0267 
0268     QCOMPARE(incidence.data(), i2.data());
0269     QCOMPARE(i2->summary(), incidence->summary());
0270     Incidence::Ptr i3 = mCalendar->incidence(incidence->uid());
0271     QCOMPARE(i3->summary(), incidence->summary());
0272 
0273     if (mIncidencesToChange > 0) {
0274         --mIncidencesToChange;
0275     }
0276 
0277     checkExitLoop();
0278 }
0279 
0280 void ETMCalendarTest::calendarIncidenceDeleted(const Incidence::Ptr &incidence, const KCalendarCore::Calendar *cal)
0281 {
0282     Q_UNUSED(cal)
0283     const QString id = incidence->customProperty("VOLATILE", "AKONADI-ID");
0284     QVERIFY(!id.isEmpty());
0285     QVERIFY(mIncidencesToDelete > 0);
0286 
0287     --mIncidencesToDelete;
0288     mLastDeletedUid = incidence->uid();
0289     checkExitLoop();
0290 }
0291 
0292 void ETMCalendarTest::testSubTodos_data()
0293 {
0294     QTest::addColumn<bool>("doClone");
0295     QTest::newRow("clone") << true;
0296     QTest::newRow("dont clone") << false;
0297 }
0298 
0299 void ETMCalendarTest::testSubTodos()
0300 {
0301     QFETCH(bool, doClone);
0302 
0303     mIncidencesToAdd = 0;
0304     mIncidencesToChange = 0;
0305     mIncidencesToDelete = 0;
0306 
0307     createTodo(tr("ta"), QString());
0308     createTodo(tr("tb"), QString());
0309     createTodo(tr("tb.1"), tr("tb"));
0310     createTodo(tr("tb.1.1"), tr("tb.1"));
0311     createTodo(tr("tb.2"), tr("tb"));
0312     createTodo(tr("tb.3"), tr("tb"));
0313     waitForIt();
0314 
0315     QVERIFY(mCalendar->childIncidences(tr("ta")).isEmpty());
0316     QCOMPARE(mCalendar->childIncidences(tr("tb")).count(), 3);
0317     QCOMPARE(mCalendar->childIncidences(tr("tb.1")).count(), 1);
0318     QVERIFY(mCalendar->childIncidences(tr("tb.1.1")).isEmpty());
0319     QVERIFY(mCalendar->childIncidences(tr("tb.2")).isEmpty());
0320 
0321     // Kill a child
0322     deleteIncidence(tr("tb.3"));
0323     waitForIt();
0324 
0325     QCOMPARE(mCalendar->childIncidences(tr("tb")).count(), 2);
0326     QCOMPARE(mCalendar->childItems(tr("tb")).count(), 2);
0327     QVERIFY(!mCalendar->incidence(tr("tb.3")));
0328 
0329     // Move a top-level to-do to a new parent
0330     Incidence::Ptr ta = mCalendar->incidence(tr("ta"));
0331     if (doClone) {
0332         ta = Incidence::Ptr(ta->clone());
0333     } else {
0334         mIncidencesToChange++;
0335     }
0336     QVERIFY(ta);
0337     Item ta_item = mCalendar->item(tr("ta"));
0338     ta_item.setPayload(ta);
0339     ta->setRelatedTo(tr("tb"));
0340     mIncidencesToChange++;
0341 
0342     auto job = new ItemModifyJob(ta_item);
0343     AKVERIFYEXEC(job);
0344     waitForIt();
0345 
0346     QCOMPARE(mCalendar->childIncidences(tr("tb")).count(), 3);
0347 
0348     // Move it to another parent now
0349     ta = mCalendar->incidence(tr("ta"));
0350     if (doClone) {
0351         ta = Incidence::Ptr(ta->clone());
0352     } else {
0353         mIncidencesToChange++;
0354     }
0355 
0356     ta_item = mCalendar->item(tr("ta"));
0357     ta->setRelatedTo(tr("tb.2"));
0358     ta_item.setPayload(ta);
0359     mIncidencesToChange++;
0360     job = new ItemModifyJob(ta_item);
0361     AKVERIFYEXEC(job);
0362     waitForIt();
0363 
0364     QCOMPARE(mCalendar->childIncidences(tr("tb")).count(), 2);
0365     QCOMPARE(mCalendar->childIncidences(tr("tb.2")).count(), 1);
0366 
0367     // Now unparent it
0368     ta = mCalendar->incidence(tr("ta"));
0369     if (doClone) {
0370         ta = Incidence::Ptr(ta->clone());
0371     } else {
0372         mIncidencesToChange++;
0373     }
0374 
0375     ta_item = mCalendar->item(tr("ta"));
0376     ta->setRelatedTo(QString());
0377     ta_item.setPayload(ta);
0378     mIncidencesToChange++;
0379     job = new ItemModifyJob(ta_item);
0380     AKVERIFYEXEC(job);
0381     waitForIt();
0382 
0383     QCOMPARE(mCalendar->childIncidences(tr("tb")).count(), 2);
0384     QVERIFY(mCalendar->childIncidences(tr("tb.2")).isEmpty());
0385 
0386     // Delete everything, so we don't have duplicate ids when the next test row runs
0387     Akonadi::Item::List itemsToDelete = mCalendar->items();
0388     mIncidencesToDelete = itemsToDelete.count();
0389     auto deleteJob = new ItemDeleteJob(itemsToDelete);
0390     AKVERIFYEXEC(deleteJob);
0391     waitForIt();
0392 }
0393 
0394 void ETMCalendarTest::testNotifyObserverBug()
0395 {
0396     // When an observer's calendarIncidenceChanged(Incidence) method got called
0397     // and that observer then called calendar->item(incidence->uid()) the retrieved item would still
0398     // have the old payload, because CalendarBase::updateItem() was still on the stack
0399     // and would only update after calendarIncidenceChanged() returned.
0400     // This test ensure that doesn't happen.
0401     const QLatin1StringView uid("todo-notify-bug");
0402     createTodo(uid, QString());
0403     waitForIt();
0404 
0405     Akonadi::Item item = mCalendar->item(uid);
0406     KCalendarCore::Incidence::Ptr incidence = KCalendarCore::Incidence::Ptr(mCalendar->incidence(uid)->clone());
0407     QVERIFY(item.isValid());
0408 
0409     // Modify it
0410     mIncidencesToChange = 1;
0411     incidence->setSummary(QStringLiteral("new-summary"));
0412     item.setPayload(incidence);
0413     auto job = new ItemModifyJob(item);
0414     AKVERIFYEXEC(job);
0415 
0416     // The test will now happen inside ETMCalendarTest::calendarIncidenceChanged()
0417     waitForIt();
0418 }
0419 
0420 void ETMCalendarTest::testUidChange()
0421 {
0422     const QLatin1StringView originalUid("original-uid");
0423     const QLatin1StringView newUid("new-uid");
0424     createTodo(originalUid, QString());
0425     waitForIt();
0426 
0427     KCalendarCore::Incidence::Ptr clone = Incidence::Ptr(mCalendar->incidence(originalUid)->clone());
0428     QCOMPARE(clone->uid(), originalUid);
0429 
0430     Akonadi::Item item = mCalendar->item(originalUid);
0431     clone->setUid(newUid);
0432     QVERIFY(item.isValid());
0433     item.setPayload(clone);
0434     mIncidencesToChange = 1;
0435     auto job = new ItemModifyJob(item);
0436     AKVERIFYEXEC(job);
0437 
0438     waitForIt();
0439 
0440     // Check that stuff still works fine
0441     KCalendarCore::Incidence::Ptr incidence = mCalendar->incidence(originalUid);
0442     QVERIFY(!incidence);
0443     incidence = mCalendar->incidence(newUid);
0444     QCOMPARE(incidence->uid(), newUid);
0445 
0446     item = mCalendar->item(originalUid);
0447     QVERIFY(!item.isValid());
0448 
0449     item = mCalendar->item(newUid);
0450     QVERIFY(item.isValid());
0451 
0452     // Mix the notify observer bug with an incidence that changes UID
0453     incidence = Incidence::Ptr(incidence->clone());
0454     incidence->setSummary(QStringLiteral("new-summary2"));
0455     item = mCalendar->item(incidence->uid());
0456     incidence->setUid(QStringLiteral("new-uid2"));
0457     item.setPayload(incidence);
0458     mIncidencesToChange = 1;
0459     job = new ItemModifyJob(item);
0460     AKVERIFYEXEC(job);
0461     waitForIt();
0462 }
0463 
0464 void ETMCalendarTest::testItem()
0465 {
0466     const QLatin1StringView uid("uid-testItem");
0467     createTodo(uid, QString());
0468     waitForIt();
0469 
0470     Incidence::Ptr incidence = mCalendar->incidence(uid);
0471     Akonadi::Item item = mCalendar->item(uid);
0472     Akonadi::Item item2 = mCalendar->item(item.id());
0473     QVERIFY(incidence);
0474     QVERIFY(item.isValid());
0475     QVERIFY(item2.isValid());
0476 
0477     Incidence::Ptr incidence1 = CalendarUtils::incidence(item);
0478     Incidence::Ptr incidence2 = CalendarUtils::incidence(item2);
0479 
0480     // The pointers should be the same
0481     QCOMPARE(incidence1.data(), incidence2.data());
0482     QCOMPARE(incidence.data(), incidence1.data());
0483 }
0484 
0485 void ETMCalendarTest::testShareETM()
0486 {
0487     createTodo(QStringLiteral("uid-123"), QString());
0488     waitForIt();
0489 
0490     auto calendar2 = new ETMCalendar(mCalendar, this);
0491     calendar2->registerObserver(this);
0492 
0493     // Uncheck our calendar
0494     KCheckableProxyModel *checkable = calendar2->checkableProxyModel();
0495     const QModelIndex firstIndex = checkable->index(0, 0);
0496     QVERIFY(firstIndex.isValid());
0497     mIncidencesToDelete = calendar2->incidences().count(); // number of incidence removed signals we get
0498     checkable->setData(firstIndex, Qt::Unchecked, Qt::CheckStateRole);
0499 
0500     // So, mCalendar has a calendar selection, while calendar2 has all it's calendars unchecked
0501     // they are sharing the same ETM.
0502     QVERIFY(!mCalendar->incidences().isEmpty());
0503     QVERIFY(calendar2->incidences().isEmpty());
0504 }
0505 
0506 void ETMCalendarTest::testFilterInvitations()
0507 {
0508     int anz = mCalendar->model()->rowCount();
0509     QString uid = QStringLiteral("invite-01");
0510     Item item;
0511     Incidence::Ptr incidence = Incidence::Ptr(new Event());
0512     KEMailSettings emailSettings;
0513     KCalendarCore::Attendee me(QStringLiteral("me"), emailSettings.getSetting(KEMailSettings::EmailAddress));
0514 
0515     item.setMimeType(Event::eventMimeType());
0516     incidence->setUid(uid);
0517     incidence->setDtStart(QDateTime::currentDateTimeUtc());
0518     incidence->setSummary(QStringLiteral("summary"));
0519 
0520     me.setStatus(KCalendarCore::Attendee::NeedsAction);
0521     incidence->addAttendee(me);
0522 
0523     item.setPayload<KCalendarCore::Incidence::Ptr>(incidence);
0524     auto job = new ItemCreateJob(item, mCollection, this);
0525     AKVERIFYEXEC(job);
0526     waitForIt();
0527     // incidence do not pop up in model
0528     QCOMPARE(mCalendar->model()->rowCount(), anz);
0529 
0530     qDebug() << "first invite ended";
0531 }
0532 
0533 void ETMCalendarTest::testFilterInvitationsChanged()
0534 {
0535     int anz = mCalendar->model()->rowCount();
0536 
0537     KEMailSettings emailSettings;
0538     KCalendarCore::Attendee me(QStringLiteral("me"), emailSettings.getSetting(KEMailSettings::EmailAddress));
0539 
0540     QString uid = QStringLiteral("invite-02");
0541     mIncidencesToAdd = 1;
0542     createIncidence(uid);
0543     waitForIt();
0544     QCOMPARE(mCalendar->model()->rowCount(), anz + 1);
0545 
0546     Incidence::Ptr incidence = mCalendar->incidence(uid);
0547     Item item = mCalendar->item(uid);
0548 
0549     incidence->addAttendee(me);
0550     incidence->setRevision(1);
0551     item.setPayload<KCalendarCore::Incidence::Ptr>(incidence);
0552 
0553     mIncidencesToDelete = 1;
0554     auto modifyJob = new ItemModifyJob(item, this);
0555     AKVERIFYEXEC(modifyJob);
0556     waitForIt();
0557     QCOMPARE(mCalendar->model()->rowCount(), anz);
0558 
0559     me.setStatus(KCalendarCore::Attendee::Accepted);
0560     incidence->clearAttendees();
0561     incidence->addAttendee(me);
0562 
0563     incidence->setRevision(2);
0564 
0565     item.setPayload<KCalendarCore::Incidence::Ptr>(incidence);
0566     item.setRevision(2);
0567     mIncidencesToAdd = 1;
0568     modifyJob = new ItemModifyJob(item, this);
0569     AKVERIFYEXEC(modifyJob);
0570     waitForIt();
0571     QCOMPARE(mCalendar->model()->rowCount(), anz + 1);
0572 }
0573 
0574 void ETMCalendarTest::waitForIt()
0575 {
0576     QTestEventLoop::instance().enterLoop(10);
0577     QVERIFY(!QTestEventLoop::instance().timeout());
0578 }
0579 
0580 void ETMCalendarTest::checkExitLoop()
0581 {
0582     // qDebug() << "checkExitLoop: current state: " << mIncidencesToDelete << mIncidencesToAdd << mIncidencesToChange;
0583     if (mIncidencesToDelete == 0 && mIncidencesToAdd == 0 && mIncidencesToChange == 0) {
0584         QTestEventLoop::instance().exitLoop();
0585     }
0586 }
0587 
0588 QTEST_AKONADIMAIN(ETMCalendarTest)
0589 
0590 #include "moc_etmcalendartest.cpp"