File indexing completed on 2024-04-28 11:33:59

0001 /*
0002   This file is part of the kcalcore library.
0003 
0004   SPDX-FileCopyrightText: 2006-2007 Allen Winter <winter@kde.org>
0005 
0006   SPDX-License-Identifier: LGPL-2.0-or-later
0007 */
0008 
0009 #include "testmemorycalendar.h"
0010 #include "filestorage.h"
0011 #include "memorycalendar.h"
0012 
0013 #include <QDebug>
0014 
0015 #include <QTest>
0016 #include <QTimeZone>
0017 QTEST_MAIN(MemoryCalendarTest)
0018 
0019 using namespace KCalendarCore;
0020 
0021 void MemoryCalendarTest::testClose()
0022 {
0023     MemoryCalendar::Ptr cal(new MemoryCalendar(QTimeZone::utc()));
0024 
0025     Event::Ptr event1(new Event);
0026     cal->addIncidence(event1);
0027 
0028     const QString nbuid = QString::fromLatin1("test-notebook");
0029     QVERIFY(cal->addNotebook(nbuid, true));
0030 
0031     Event::Ptr event2(new Event);
0032     cal->addIncidence(event2);
0033     cal->setNotebook(event2, nbuid);
0034 
0035     QCOMPARE(cal->incidences().count(), 2);
0036     QVERIFY(cal->instance(event1->instanceIdentifier()));
0037     QVERIFY(cal->instance(event2->instanceIdentifier()));
0038     QVERIFY(cal->event(event1->uid()));
0039     QVERIFY(cal->event(event2->uid()));
0040     QCOMPARE(cal->incidences(nbuid).count(), 1);
0041 
0042     cal->close();
0043 
0044     QVERIFY(!cal->event(event1->uid()));
0045     QVERIFY(!cal->event(event2->uid()));
0046     QVERIFY(cal->incidences().isEmpty());
0047     QVERIFY(cal->incidences(nbuid).isEmpty());
0048 }
0049 
0050 void MemoryCalendarTest::testValidity()
0051 {
0052     MemoryCalendar::Ptr cal(new MemoryCalendar(QTimeZone::utc()));
0053     cal->setProductId(QStringLiteral("fredware calendar"));
0054     QVERIFY(cal->productId() == QLatin1String("fredware calendar"));
0055     QVERIFY(cal->timeZoneId() == QByteArrayLiteral("UTC"));
0056     QVERIFY(cal->timeZone() == QTimeZone::utc());
0057     cal->close();
0058 }
0059 
0060 void MemoryCalendarTest::testInvalidTimeZone()
0061 {
0062     MemoryCalendar::Ptr cal(new MemoryCalendar(QTimeZone()));
0063     // On invalid time zone, fallback to system time zone.
0064     QVERIFY(cal->timeZone() == QTimeZone::systemTimeZone());
0065 }
0066 
0067 void MemoryCalendarTest::testEvents()
0068 {
0069     MemoryCalendar::Ptr cal(new MemoryCalendar(QTimeZone::utc()));
0070     cal->setProductId(QStringLiteral("fredware calendar"));
0071     QDate dt = QDate::currentDate();
0072 
0073     Event::Ptr event1 = Event::Ptr(new Event());
0074     event1->setUid(QStringLiteral("1"));
0075     event1->setDtStart(QDateTime(dt, {}));
0076     event1->setDtEnd(QDateTime(dt, {}).addDays(1));
0077     event1->setAllDay(true);
0078     event1->setSummary(QStringLiteral("Event1 Summary"));
0079     event1->setDescription(QStringLiteral("This is a description of the first event"));
0080     event1->setLocation(QStringLiteral("the place"));
0081 
0082     Event::Ptr event2 = Event::Ptr(new Event());
0083     event2->setUid(QStringLiteral("2"));
0084     event2->setDtStart(QDateTime(dt, {}).addDays(1));
0085     event2->setDtEnd(QDateTime(dt, {}).addDays(2));
0086     event2->setAllDay(true);
0087     event2->setSummary(QStringLiteral("Event2 Summary"));
0088     event2->setDescription(QStringLiteral("This is a description of the second event"));
0089     event2->setLocation(QStringLiteral("the other place"));
0090 
0091     QVERIFY(cal->addEvent(event1));
0092     QVERIFY(cal->addEvent(event2));
0093 
0094     FileStorage store(cal, QStringLiteral("foo.ics"));
0095     QVERIFY(store.save());
0096     cal->close();
0097     QFile::remove(QStringLiteral("foo.ics"));
0098 }
0099 
0100 void MemoryCalendarTest::testIncidences()
0101 {
0102     MemoryCalendar::Ptr cal(new MemoryCalendar(QTimeZone::utc()));
0103     cal->setProductId(QStringLiteral("fredware calendar"));
0104     QDate dt = QDate::currentDate();
0105 
0106     Event::Ptr event1 = Event::Ptr(new Event());
0107     event1->setUid(QStringLiteral("1"));
0108     event1->setDtStart(QDateTime(dt, {}));
0109     event1->setDtEnd(QDateTime(dt, {}).addDays(1));
0110     event1->setAllDay(true);
0111     event1->setSummary(QStringLiteral("Event1 Summary"));
0112     event1->setDescription(QStringLiteral("This is a description of the first event"));
0113     event1->setLocation(QStringLiteral("the place"));
0114 
0115     Event::Ptr event2 = Event::Ptr(new Event());
0116     event2->setUid(QStringLiteral("2"));
0117     event2->setDtStart(QDateTime(dt, {}).addDays(1));
0118     event2->setDtEnd(QDateTime(dt, {}).addDays(2));
0119     event2->setAllDay(true);
0120     event2->setSummary(QStringLiteral("Event2 Summary"));
0121     event2->setDescription(QStringLiteral("This is a description of the second event"));
0122     event2->setLocation(QStringLiteral("the other place"));
0123 
0124     QVERIFY(cal->addEvent(event1));
0125     QVERIFY(cal->addEvent(event2));
0126 
0127     Todo::Ptr todo1 = Todo::Ptr(new Todo());
0128     todo1->setUid(QStringLiteral("3"));
0129     todo1->setDtStart(QDateTime(dt, {}).addDays(1));
0130     todo1->setDtDue(QDateTime(dt, {}).addDays(2));
0131     todo1->setAllDay(true);
0132     todo1->setSummary(QStringLiteral("Todo1 Summary"));
0133     todo1->setDescription(QStringLiteral("This is a description of a todo"));
0134     todo1->setLocation(QStringLiteral("this place"));
0135 
0136     Todo::Ptr todo2 = Todo::Ptr(new Todo());
0137     todo2->setUid(QStringLiteral("4"));
0138     todo2->setDtStart(QDateTime(dt, {}).addDays(1));
0139     todo2->setAllDay(true);
0140     todo2->setSummary(QStringLiteral("<qt><h1>Todo2 Summary</h1></qt>"), true);
0141     todo2->setDescription(QStringLiteral("This is a description of a todo"));
0142     todo2->setLocation(QStringLiteral("<html><a href=\"http://www.fred.com\">this place</a></html>"), true);
0143 
0144     QVERIFY(cal->addTodo(todo1));
0145     QVERIFY(cal->addTodo(todo2));
0146 
0147     FileStorage store(cal, QStringLiteral("foo.ics"));
0148     QVERIFY(store.save());
0149     cal->close();
0150 
0151     QVERIFY(store.load());
0152     Todo::Ptr todo = cal->incidence(QStringLiteral("4")).staticCast<Todo>();
0153     QVERIFY(todo->uid() == QLatin1Char('4'));
0154     QVERIFY(todo->summaryIsRich());
0155     QVERIFY(todo->locationIsRich());
0156     cal->close();
0157     QFile::remove(QStringLiteral("foo.ics"));
0158 }
0159 
0160 void MemoryCalendarTest::testRelationsCrash()
0161 {
0162     // Before, there was a crash that occurred only when reloading a calendar in which
0163     // the incidences had special relations.
0164     // This test tests that scenario, and will crash if it fails.
0165     MemoryCalendar::Ptr cal(new MemoryCalendar(QTimeZone::utc()));
0166     FileStorage store1(cal, QLatin1String(ICALTESTDATADIR) + QLatin1String("test_relations.ics"));
0167     QVERIFY(store1.load());
0168     const Todo::List oldTodos = cal->todos();
0169     qDebug() << "Loaded " << oldTodos.count() << " todos into oldTodos.";
0170 
0171     FileStorage store2(cal, QLatin1String(ICALTESTDATADIR) + QLatin1String("test_relations.ics"));
0172     QVERIFY(store2.load());
0173     const Todo::List newTodos = cal->todos();
0174     qDebug() << "Loaded " << newTodos.count() << " into newTodos.";
0175 
0176     // We can saftely access the old deleted todos here, since they are not really deleted
0177     // and are still kept in a map of deleted items somewhere.
0178     //
0179     // Here we make sure that non of the old items have connections to the new items, and
0180     // the other way around.
0181 
0182     // This doesn't makes sense so i commented it. when you load a calendar the second time
0183     // it reuses what it can, so oldTodo == newTodo
0184 
0185     /*  foreach (const Todo::Ptr &oldTodo, oldTodos ) {
0186         foreach (const Todo::Ptr &newTodo, newTodos ) {
0187           QVERIFY( oldTodo != newTodo );
0188 
0189           // Make sure that none of the new todos point to an old, deleted todo
0190           QVERIFY( newTodo->relatedTo() != oldTodo );
0191           QVERIFY( !newTodo->relations().contains( oldTodo ) );
0192 
0193           // Make sure that none of the old todos point to a new todo
0194           QVERIFY( oldTodo->relatedTo() != newTodo );
0195           QVERIFY( !oldTodo->relations().contains( newTodo ) );
0196         }
0197       }
0198     */
0199     cal->close();
0200 }
0201 
0202 void MemoryCalendarTest::testRecurrenceExceptions()
0203 {
0204     MemoryCalendar::Ptr cal(new MemoryCalendar(QTimeZone::utc()));
0205     cal->setProductId(QStringLiteral("fredware calendar"));
0206     QDate dt = QDate::currentDate();
0207     QDateTime start(dt, {});
0208 
0209     Event::Ptr event1 = Event::Ptr(new Event());
0210     event1->setUid(QStringLiteral("1"));
0211     event1->setDtStart(start);
0212     event1->setDtEnd(start.addDays(1));
0213     event1->setSummary(QStringLiteral("Event1 Summary"));
0214     event1->recurrence()->setDaily(1);
0215     event1->recurrence()->setDuration(3);
0216     QVERIFY(cal->addEvent(event1));
0217 
0218     const QDateTime recurrenceId = event1->dtStart().addDays(1);
0219     Event::Ptr exception1 = cal->createException(event1, recurrenceId).staticCast<Event>();
0220     QCOMPARE(exception1->recurrenceId(), recurrenceId);
0221     QCOMPARE(exception1->uid(), event1->uid());
0222     exception1->setSummary(QStringLiteral("exception"));
0223 
0224     QVERIFY(exception1);
0225     QVERIFY(cal->addEvent(exception1));
0226 
0227     QCOMPARE(cal->event(event1->uid()), event1);
0228     QCOMPARE(cal->event(event1->uid(), recurrenceId), exception1);
0229 
0230     const Event::List incidences = cal->rawEvents(start.date(), start.addDays(3).date(), start.timeZone());
0231     // Contains incidence and exception
0232     QCOMPARE(incidences.size(), 2);
0233 
0234     // Returns only exceptions for an event
0235     const Event::List exceptions = cal->eventInstances(event1);
0236     QCOMPARE(exceptions.size(), 1);
0237     QCOMPARE(exceptions.first()->uid(), event1->uid());
0238     QCOMPARE(exceptions.first()->summary(), exception1->summary());
0239 }
0240 
0241 void MemoryCalendarTest::testChangeRecurId()
0242 {
0243     // When we change the recurring id, internal hashtables should be updated.
0244 
0245     MemoryCalendar::Ptr cal(new MemoryCalendar(QTimeZone::utc()));
0246     QDateTime start(QDate::currentDate(), {});
0247 
0248     // Add main event
0249     Event::Ptr event1 = Event::Ptr(new Event());
0250     const QString uid = QStringLiteral("1");
0251     event1->setUid(uid);
0252     event1->setDtStart(start);
0253     event1->setDtEnd(start.addDays(1));
0254     event1->setAllDay(true);
0255     event1->setSummary(QStringLiteral("Event1 Summary"));
0256     event1->recurrence()->setDaily(1);
0257     event1->recurrence()->setDuration(3);
0258     QVERIFY(cal->addEvent(event1));
0259 
0260     // Add exception event:
0261     const QDateTime recurrenceId = event1->dtStart().addDays(1);
0262     Event::Ptr exception1 = cal->createException(event1, recurrenceId).staticCast<Event>();
0263     QCOMPARE(exception1->recurrenceId(), recurrenceId);
0264     QCOMPARE(exception1->uid(), event1->uid());
0265     exception1->setSummary(QStringLiteral("exception"));
0266     QVERIFY(exception1);
0267     QVERIFY(cal->addEvent(exception1));
0268 
0269     const QString oldIdentifier = exception1->instanceIdentifier();
0270     Incidence::Ptr foo = cal->instance(oldIdentifier);
0271     QVERIFY(foo && foo->hasRecurrenceId());
0272     // Now change the recurring id!
0273     exception1->setRecurrenceId(start.addDays(2));
0274     const QString newIdentifier = exception1->instanceIdentifier();
0275     QVERIFY(oldIdentifier != newIdentifier);
0276 
0277     foo = cal->instance(oldIdentifier);
0278     QVERIFY(!foo);
0279 
0280     foo = cal->instance(newIdentifier);
0281     QVERIFY(foo);
0282 
0283     // Test hashing
0284     Incidence::List incidences = cal->incidences();
0285     QVERIFY(incidences.count() == 2);
0286 
0287     QDateTime newRecId = start.addDays(2);
0288     Incidence::Ptr main = cal->incidence(uid);
0289     Incidence::Ptr exception = cal->incidence(uid, newRecId);
0290     Incidence::Ptr noException = cal->incidence(uid, recurrenceId);
0291     QVERIFY(!noException);
0292     QVERIFY(main);
0293     QVERIFY(exception);
0294     QVERIFY(exception->recurrenceId() == newRecId);
0295     QVERIFY(exception->summary() == QLatin1String("exception"));
0296     QVERIFY(main->summary() == event1->summary());
0297 }
0298 
0299 void MemoryCalendarTest::testRawEventsForDate()
0300 {
0301     // We're checking that events at a date in a given time zone
0302     // are properly returned for the day after / before if
0303     // the calendar is for another time zone.
0304     MemoryCalendar::Ptr cal(new MemoryCalendar(QTimeZone::utc()));
0305 
0306     Event::Ptr event = Event::Ptr(new Event());
0307     event->setDtStart(QDateTime(QDate(2019, 10, 29), QTime(1, 30), QTimeZone("Asia/Ho_Chi_Minh")));
0308 
0309     QVERIFY(cal->addEvent(event));
0310 
0311     QCOMPARE(cal->rawEventsForDate(QDate(2019, 10, 28)).count(), 1);
0312     QCOMPARE(cal->rawEventsForDate(QDate(2019, 10, 29), QTimeZone("Asia/Ho_Chi_Minh")).count(), 1);
0313 
0314     cal->setTimeZoneId("Asia/Ho_Chi_Minh");
0315     QCOMPARE(cal->rawEventsForDate(QDate(2019, 10, 29)).count(), 1);
0316     QCOMPARE(cal->rawEventsForDate(QDate(2019, 10, 28), QTimeZone::utc()).count(), 1);
0317 
0318     event->setDtStart(QDateTime(QDate(2019, 10, 30), QTime(23, 00), QTimeZone::utc()));
0319     QCOMPARE(cal->rawEventsForDate(QDate(2019, 10, 31)).count(), 1);
0320     QCOMPARE(cal->rawEventsForDate(QDate(2019, 10, 30), QTimeZone::utc()).count(), 1);
0321 
0322     QVERIFY(cal->deleteIncidence(event));
0323     QCOMPARE(cal->rawEventsForDate(QDate(2019, 10, 31)).count(), 0);
0324 
0325     // Multi-days events are treated differently.
0326     event->setDtEnd(QDateTime(QDate(2019, 10, 31), QTime(23, 00), QTimeZone::utc()));
0327     QVERIFY(cal->addEvent(event));
0328     QCOMPARE(cal->rawEventsForDate(QDate(2019, 10, 31)).count(), 1);
0329     QCOMPARE(cal->rawEventsForDate(QDate(2019, 11, 1)).count(), 1);
0330 
0331     cal->close();
0332 }
0333 
0334 void MemoryCalendarTest::testVisibility()
0335 {
0336     MemoryCalendar::Ptr cal(new MemoryCalendar(QTimeZone::utc()));
0337     const QString notebook = QLatin1String("Notebook");
0338 
0339     QVERIFY(cal->addNotebook(notebook, true));
0340     QVERIFY(cal->isVisible(notebook));
0341 
0342     Event::Ptr event = Event::Ptr(new Event());
0343     QVERIFY(cal->addIncidence(event));
0344     QVERIFY(cal->setNotebook(event, notebook));
0345 
0346     QVERIFY(cal->isVisible(event));
0347 
0348     QVERIFY(cal->updateNotebook(notebook, false));
0349     QVERIFY(!cal->isVisible(notebook));
0350     QVERIFY(!cal->isVisible(event));
0351 }
0352 
0353 class TestCalendarObserver: public Calendar::CalendarObserver
0354 {
0355 public:
0356     TestCalendarObserver(const Calendar::Ptr &cal)
0357         : mCalendar(cal)
0358     {
0359         cal->registerObserver(this);
0360     }
0361     ~TestCalendarObserver()
0362     {
0363         mCalendar->unregisterObserver(this);
0364     }
0365     void calendarIncidenceChanged(const Incidence::Ptr &incidence) override
0366     {
0367         mUpdated.append(incidence);
0368     }
0369     bool hasIncidenceChanged(const Incidence::Ptr &incidence) const
0370     {
0371         return std::find_if(mUpdated.constBegin(), mUpdated.constEnd(),
0372                             [incidence] (const Incidence::Ptr &it) {
0373                                 return (it->uid() == incidence->uid()
0374                                         && it->recurrenceId() == incidence->recurrenceId());
0375                             }) != mUpdated.constEnd();
0376     }
0377     Incidence::List mUpdated;
0378 private:
0379     Calendar::Ptr mCalendar;
0380 };
0381 
0382 void MemoryCalendarTest::testNotebookChange()
0383 {
0384     MemoryCalendar::Ptr cal(new MemoryCalendar(QTimeZone::utc()));
0385     TestCalendarObserver observer(cal);
0386     const QString notebook1 = QLatin1String("Notebook1");
0387     const QString notebook2 = QLatin1String("Notebook2");
0388 
0389     QVERIFY(cal->addNotebook(notebook1, true));
0390     QVERIFY(cal->addNotebook(notebook2, true));
0391 
0392     Event::Ptr event = Event::Ptr(new Event());
0393     event->setDtStart(QDateTime(QDate(2022, 3, 23), QTime(10, 12), Qt::UTC));
0394     event->recurrence()->setDaily(1);
0395     Incidence::Ptr exception = Calendar::createException(event, event->dtStart().addDays(3));
0396     QVERIFY(exception);
0397     exception->setDtStart(exception->recurrenceId().addSecs(1800));
0398     QVERIFY(cal->addIncidence(event));
0399     QVERIFY(cal->addIncidence(exception));
0400     QVERIFY(cal->notebook(event).isEmpty());
0401     QVERIFY(cal->notebook(exception).isEmpty());
0402 
0403     QVERIFY(observer.mUpdated.isEmpty());
0404     QVERIFY(cal->setNotebook(event, notebook1));
0405     QCOMPARE(cal->notebook(event), notebook1);
0406     QCOMPARE(cal->notebook(exception), notebook1);
0407     QVERIFY(observer.hasIncidenceChanged(event));
0408     QVERIFY(observer.hasIncidenceChanged(exception));
0409 
0410     observer.mUpdated.clear();
0411     QVERIFY(cal->setNotebook(event, notebook2));
0412     QCOMPARE(cal->notebook(event), notebook2);
0413     QCOMPARE(cal->notebook(exception), notebook2);
0414     QVERIFY(observer.hasIncidenceChanged(event));
0415     QVERIFY(observer.hasIncidenceChanged(exception));
0416 }
0417 
0418 void MemoryCalendarTest::testRawEvents()
0419 {
0420     MemoryCalendar::Ptr cal(new MemoryCalendar(QTimeZone::utc()));
0421 
0422     Event::Ptr event = Event::Ptr(new Event());
0423     // This event span in 20201011T2330Z - 20201012T2330Z
0424     event->setDtStart(QDateTime(QDate(2020, 10, 12), QTime(1, 30), QTimeZone("Europe/Paris")));
0425     event->setDtEnd(QDateTime(QDate(2020, 10, 13), QTime(1, 30), QTimeZone("Europe/Paris")));
0426 
0427     QVERIFY(cal->addEvent(event));
0428 
0429     // Not full-event inclusive by default, UTC timezone.
0430     QCOMPARE(cal->rawEvents(QDate(2020, 10, 1), QDate(2020, 10, 10)).count(), 0);
0431     QCOMPARE(cal->rawEvents(QDate(2020, 10, 11), QDate(2020, 10, 11)).count(), 1);
0432     QCOMPARE(cal->rawEvents(QDate(2020, 10, 12), QDate(2020, 10, 12)).count(), 1);
0433     QCOMPARE(cal->rawEvents(QDate(2020, 10, 13), QDate(2020, 10, 31)).count(), 0);
0434     QCOMPARE(cal->rawEvents(QDate(), QDate(2020, 10, 10)).count(), 0);
0435     QCOMPARE(cal->rawEvents(QDate(), QDate(2020, 10, 11)).count(), 1);
0436     QCOMPARE(cal->rawEvents(QDate(2020, 10, 13), QDate()).count(), 0);
0437     QCOMPARE(cal->rawEvents(QDate(2020, 10, 12), QDate()).count(), 1);
0438 
0439     // Changing the time zone we are considering the dates in.
0440     QCOMPARE(cal->rawEvents(QDate(2020, 10, 1), QDate(2020, 10, 11), QTimeZone("Europe/Paris")).count(), 0);
0441     QCOMPARE(cal->rawEvents(QDate(2020, 10, 12), QDate(2020, 10, 12), QTimeZone("Europe/Paris")).count(), 1);
0442     QCOMPARE(cal->rawEvents(QDate(2020, 10, 13), QDate(2020, 10, 13), QTimeZone("Europe/Paris")).count(), 1);
0443     QCOMPARE(cal->rawEvents(QDate(2020, 10, 14), QDate(2020, 10, 31), QTimeZone("Europe/Paris")).count(), 0);
0444     QCOMPARE(cal->rawEvents(QDate(), QDate(2020, 10, 11), QTimeZone("Europe/Paris")).count(), 0);
0445     QCOMPARE(cal->rawEvents(QDate(), QDate(2020, 10, 12), QTimeZone("Europe/Paris")).count(), 1);
0446     QCOMPARE(cal->rawEvents(QDate(2020, 10, 14), QDate(), QTimeZone("Europe/Paris")).count(), 0);
0447     QCOMPARE(cal->rawEvents(QDate(2020, 10, 13), QDate(), QTimeZone("Europe/Paris")).count(), 1);
0448 
0449     // Full event must be in the span.
0450     QCOMPARE(cal->rawEvents(QDate(2020, 10, 1), QDate(2020, 10, 10), QTimeZone(), true).count(), 0);
0451     QCOMPARE(cal->rawEvents(QDate(2020, 10, 11), QDate(2020, 10, 11), QTimeZone(), true).count(), 0);
0452     QCOMPARE(cal->rawEvents(QDate(2020, 10, 12), QDate(2020, 10, 12), QTimeZone(), true).count(), 0);
0453     QCOMPARE(cal->rawEvents(QDate(2020, 10, 11), QDate(2020, 10, 12), QTimeZone(), true).count(), 1);
0454     QCOMPARE(cal->rawEvents(QDate(2020, 10, 13), QDate(2020, 10, 31), QTimeZone(), true).count(), 0);
0455     QCOMPARE(cal->rawEvents(QDate(), QDate(2020, 10, 10), QTimeZone(), true).count(), 0);
0456     QCOMPARE(cal->rawEvents(QDate(), QDate(2020, 10, 11), QTimeZone(), true).count(), 0);
0457     QCOMPARE(cal->rawEvents(QDate(), QDate(2020, 10, 12), QTimeZone(), true).count(), 1);
0458     QCOMPARE(cal->rawEvents(QDate(2020, 10, 13), QDate(), QTimeZone(), true).count(), 0);
0459     QCOMPARE(cal->rawEvents(QDate(2020, 10, 12), QDate(), QTimeZone(), true).count(), 0);
0460     QCOMPARE(cal->rawEvents(QDate(2020, 10, 11), QDate(), QTimeZone(), true).count(), 1);
0461 
0462     cal->close();
0463 }
0464 
0465 void MemoryCalendarTest::testDeleteIncidence()
0466 {
0467     MemoryCalendar::Ptr cal(new MemoryCalendar(QTimeZone::utc()));
0468 
0469     Event::Ptr event = Event::Ptr(new Event());
0470     event->setDtStart(QDateTime(QDate(2021, 1, 4), QTime(10, 13), QTimeZone("Europe/Paris")));
0471 
0472     QVERIFY(cal->addEvent(event));
0473     QVERIFY(cal->instance(event->instanceIdentifier()));
0474 
0475     QVERIFY(cal->deleteIncidence(event));
0476     QVERIFY(cal->instance(event->instanceIdentifier()).isNull());
0477 
0478     event->recurrence()->setDaily(1);
0479     event->recurrence()->setDuration(3);
0480     QVERIFY(cal->addEvent(event));
0481     QVERIFY(cal->instance(event->instanceIdentifier()));
0482 
0483     Event::Ptr exception = Event::Ptr(event->clone());
0484     exception->recurrence()->clear();
0485     exception->setRecurrenceId(event->dtStart().addDays(1));
0486     exception->setDtStart(event->dtStart().addDays(1).addSecs(3600));
0487     QVERIFY(cal->addEvent(exception));
0488     QVERIFY(cal->instance(exception->instanceIdentifier()));
0489 
0490     Event::Ptr exception2 = Event::Ptr(event->clone());
0491     exception2->recurrence()->clear();
0492     exception2->setRecurrenceId(event->dtStart().addDays(2));
0493     exception2->setDtStart(event->dtStart().addDays(2).addSecs(-3600));
0494     QVERIFY(cal->addEvent(exception2));
0495     QVERIFY(cal->instance(exception2->instanceIdentifier()));
0496 
0497     QVERIFY(cal->deleteIncidence(exception));
0498     QVERIFY(cal->incidence(event->uid(), exception->recurrenceId()).isNull());
0499     QVERIFY(!cal->deleteIncidence(exception));
0500     QVERIFY(cal->incidence(event->uid(), exception2->recurrenceId()));
0501     QVERIFY(cal->incidence(event->uid()));
0502 
0503     QVERIFY(cal->deleteIncidence(event));
0504     QVERIFY(cal->incidence(event->uid(), exception2->recurrenceId()).isNull());
0505     QVERIFY(cal->incidence(event->uid()).isNull());
0506 }
0507 
0508 void MemoryCalendarTest::testUpdateIncidence()
0509 {
0510     MemoryCalendar::Ptr cal(new MemoryCalendar(QTimeZone::utc()));
0511 
0512     const QDateTime dt(QDate(2021, 02, 25), QTime(14, 0), Qt::UTC);
0513     Event::Ptr event(new Event());
0514     event->setCreated(dt);
0515     event->setLastModified(dt);
0516     event->setDtStart(dt);
0517     event->setDtEnd(dt.addSecs(3600));
0518 
0519     // Adding event to cal, makes cal an observer of event.
0520     QVERIFY(cal->addIncidence(event));
0521     QCOMPARE(cal->rawEventsForDate(dt.date(), dt.timeZone()).count(), 1);
0522 
0523     QVERIFY(cal->updateLastModifiedOnChange());
0524 
0525     const QDateTime now = QDateTime::currentDateTimeUtc();
0526 
0527     // Any single modification is updating the lastModified field.
0528     event->setSummary(QString::fromLatin1("test"));
0529     QVERIFY(event->lastModified().secsTo(now) < 5);
0530 
0531     // Reset lastModified field.
0532     event->setLastModified(dt);
0533     QCOMPARE(event->lastModified(), dt);
0534 
0535     // Any modification within a startUpdates()/endUpdates() should not touch
0536     // lastModified field, before the changes are completed.
0537     event->startUpdates();
0538     QVERIFY(cal->rawEventsForDate(dt.date(), dt.timeZone()).isEmpty());
0539     event->setSummary(QString::fromLatin1("test again"));
0540     QCOMPARE(event->lastModified(), dt);
0541     event->endUpdates();
0542     QVERIFY(event->lastModified().secsTo(now) < 5);
0543     QCOMPARE(cal->rawEventsForDate(dt.date(), dt.timeZone()).count(), 1);
0544 
0545     // Reset lastModified field.
0546     event->setLastModified(dt);
0547     QCOMPARE(event->lastModified(), dt);
0548 
0549     // Don't update lastModified on change.
0550     cal->setUpdateLastModifiedOnChange(false);
0551     event->setSummary(QString::fromLatin1("last test"));
0552     QCOMPARE(event->lastModified(), dt);
0553 }
0554 
0555 #include "moc_testmemorycalendar.cpp"