File indexing completed on 2024-04-21 03:52:40
0001 /* 0002 This file is part of the kcalcore library. 0003 0004 SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.net> 0005 SPDX-FileContributor: Sergio Martins <sergio.martins@kdab.com> 0006 0007 SPDX-License-Identifier: LGPL-2.0-or-later 0008 */ 0009 0010 #include "testicalformat.h" 0011 #include "event.h" 0012 #include "icalformat.h" 0013 #include "memorycalendar.h" 0014 #include "occurrenceiterator.h" 0015 0016 #include <QTest> 0017 #include <QTimeZone> 0018 0019 QTEST_MAIN(ICalFormatTest) 0020 0021 using namespace KCalendarCore; 0022 0023 void ICalFormatTest::testDeserializeSerialize() 0024 { 0025 ICalFormat format; 0026 0027 const QString serializedCalendar = QLatin1String( 0028 "BEGIN:VCALENDAR\n" 0029 "PRODID:-//IDN nextcloud.com//Calendar app 2.0.4//EN\n" 0030 "VERSION:2.0\n" 0031 "BEGIN:VEVENT\n" 0032 "CREATED:20201103T161248Z\n" 0033 "DTSTAMP:20201103T161340Z\n" 0034 "LAST-MODIFIED:20201103T161340Z\n" 0035 "SEQUENCE:2\n" 0036 "UID:bd1d299d-3b03-4514-be69-e680ad2ff884\n" 0037 "DTSTART;TZID=Europe/Paris:20201103T100000\n" 0038 "DTEND;TZID=Europe/Paris:20201103T110000\n" 0039 "SUMMARY:test recur\n" 0040 "RRULE:FREQ=DAILY;COUNT=4\n" 0041 "END:VEVENT\n" 0042 "BEGIN:VEVENT\n" 0043 "CREATED:20201103T161823Z\n" 0044 "DTSTAMP:20201103T161823Z\n" 0045 "LAST-MODIFIED:20201103T161823Z\n" 0046 "SEQUENCE:1\n" 0047 "UID:bd1d299d-3b03-4514-be69-e680ad2ff884\n" 0048 "DTSTART;TZID=Europe/Paris:20201104T111500\n" 0049 "DTEND;TZID=Europe/Paris:20201104T121500\n" 0050 "SUMMARY:test recur\n" 0051 "COLOR:khaki\n" 0052 "RECURRENCE-ID;TZID=Europe/Paris:20201104T100000\n" 0053 "END:VEVENT\n" 0054 "END:VCALENDAR"); 0055 MemoryCalendar::Ptr calendar = MemoryCalendar::Ptr(new MemoryCalendar(QTimeZone::utc())); 0056 QVERIFY(format.fromString(calendar, serializedCalendar)); 0057 const QString uid = QString::fromLatin1("bd1d299d-3b03-4514-be69-e680ad2ff884"); 0058 Incidence::Ptr parent = calendar->incidence(uid); 0059 QVERIFY(parent); 0060 const QDateTime start(QDate(2020, 11, 3), QTime(9, 0), QTimeZone::utc()); 0061 QCOMPARE(parent->dtStart(), start); 0062 QCOMPARE(parent.staticCast<Event>()->dtEnd(), start.addSecs(3600)); 0063 QCOMPARE(parent->summary(), QString::fromLatin1("test recur")); 0064 QCOMPARE(parent->revision(), 2); 0065 Recurrence *recur = parent->recurrence(); 0066 QVERIFY(recur->recurs()); 0067 QCOMPARE(recur->duration(), 4); 0068 QCOMPARE(recur->recurrenceType(), static_cast<ushort>(Recurrence::rDaily)); 0069 0070 Incidence::Ptr occurrence = calendar->incidence(uid, start.addDays(1)); 0071 QVERIFY(occurrence); 0072 const QDateTime startOcc(QDate(2020, 11, 4), QTime(10, 15), QTimeZone::utc()); 0073 QCOMPARE(occurrence->dtStart(), startOcc); 0074 QCOMPARE(occurrence.staticCast<Event>()->dtEnd(), startOcc.addSecs(3600)); 0075 QCOMPARE(occurrence->color(), QString::fromLatin1("khaki")); 0076 QCOMPARE(occurrence->summary(), QString::fromLatin1("test recur")); 0077 QCOMPARE(occurrence->revision(), 1); 0078 QVERIFY(occurrence->hasRecurrenceId()); 0079 QCOMPARE(occurrence->recurrenceId(), start.addDays(1)); 0080 0081 const QString serialization = format.toString(calendar); 0082 QVERIFY(!serialization.isEmpty()); 0083 MemoryCalendar::Ptr check = MemoryCalendar::Ptr(new MemoryCalendar(QTimeZone::utc())); 0084 QVERIFY(format.fromString(check, serialization)); 0085 Incidence::Ptr reparent = check->incidence(uid); 0086 QVERIFY(reparent); 0087 QCOMPARE(*parent, *reparent); 0088 Incidence::Ptr reoccurence = check->incidence(uid, start.addDays(1)); 0089 QVERIFY(reoccurence); 0090 QCOMPARE(*occurrence, *reoccurence); 0091 } 0092 0093 void ICalFormatTest::testCharsets() 0094 { 0095 ICalFormat format; 0096 const QDate currentDate = QDate::currentDate(); 0097 Event::Ptr event = Event::Ptr(new Event()); 0098 event->setUid(QStringLiteral("12345")); 0099 event->setDtStart(QDateTime(currentDate, {})); 0100 event->setDtEnd(QDateTime(currentDate.addDays(1), {})); 0101 event->setAllDay(true); 0102 0103 // ü 0104 const QChar latin1_umlaut[] = {(QChar)0xFC, QLatin1Char('\0')}; 0105 event->setSummary(QString(latin1_umlaut)); 0106 0107 // Test if toString( Incidence ) didn't mess charsets 0108 const QString serialized = format.toString(event.staticCast<Incidence>()); 0109 const QChar utf_umlaut[] = {(QChar)0xC3, (QChar)0XBC, QLatin1Char('\0')}; 0110 QVERIFY(serialized.toUtf8().contains(QString(utf_umlaut).toLatin1().constData())); 0111 QVERIFY(!serialized.toUtf8().contains(QString(latin1_umlaut).toLatin1().constData())); 0112 QVERIFY(serialized.toLatin1().contains(QString(latin1_umlaut).toLatin1().constData())); 0113 QVERIFY(!serialized.toLatin1().contains(QString(utf_umlaut).toLatin1().constData())); 0114 0115 // test fromString( QString ) 0116 const QString serializedCalendar = QLatin1String("BEGIN:VCALENDAR\nPRODID:-//K Desktop Environment//NONSGML libkcal 3.2//EN\nVERSION:2.0\n") + serialized 0117 + QLatin1String("\nEND:VCALENDAR"); 0118 0119 Incidence::Ptr event2 = format.fromString(serializedCalendar); 0120 QVERIFY(event->summary() == event2->summary()); 0121 QVERIFY(event2->summary().toUtf8() == QByteArray(QString(utf_umlaut).toLatin1().constData())); 0122 0123 // test save() 0124 MemoryCalendar::Ptr calendar(new MemoryCalendar(QTimeZone::utc())); 0125 calendar->addIncidence(event); 0126 QVERIFY(format.save(calendar, QLatin1String("hommer.ics"))); 0127 0128 // Make sure hommer.ics is in UTF-8 0129 QFile file(QStringLiteral("hommer.ics")); 0130 QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text)); 0131 0132 const QByteArray bytesFromFile = file.readAll(); 0133 QVERIFY(bytesFromFile.contains(QString(utf_umlaut).toLatin1().constData())); 0134 QVERIFY(!bytesFromFile.contains(QString(latin1_umlaut).toLatin1().constData())); 0135 file.close(); 0136 0137 // Test load: 0138 MemoryCalendar::Ptr calendar2(new MemoryCalendar(QTimeZone::utc())); 0139 QVERIFY(format.load(calendar2, QLatin1String("hommer.ics"))); 0140 QVERIFY(calendar2->incidences().count() == 1); 0141 0142 Event::Ptr loadedEvent = calendar2->incidences().at(0).staticCast<Event>(); 0143 QVERIFY(loadedEvent->summary().toUtf8() == QByteArray(QString(utf_umlaut).toLatin1().constData())); 0144 QVERIFY(*loadedEvent == *event); 0145 0146 // Test fromRawString() 0147 MemoryCalendar::Ptr calendar3(new MemoryCalendar(QTimeZone::utc())); 0148 QVERIFY(format.fromRawString(calendar3, bytesFromFile)); 0149 QVERIFY(calendar3->incidences().count() == 1); 0150 QVERIFY(*calendar3->incidences().at(0) == *event); 0151 0152 QFile::remove(QStringLiteral("hommer.ics")); 0153 } 0154 0155 void ICalFormatTest::testVolatileProperties() 0156 { 0157 // Volatile properties are not written to the serialized data 0158 ICalFormat format; 0159 const QDate currentDate = QDate::currentDate(); 0160 Event::Ptr event = Event::Ptr(new Event()); 0161 event->setUid(QStringLiteral("12345")); 0162 event->setDtStart(QDateTime(currentDate, {})); 0163 event->setDtEnd(QDateTime(currentDate.addDays(1), {})); 0164 event->setAllDay(true); 0165 event->setCustomProperty("VOLATILE", "FOO", QStringLiteral("BAR")); 0166 QString string = format.toICalString(event); 0167 Incidence::Ptr incidence = format.fromString(string); 0168 0169 QCOMPARE(incidence->uid(), QStringLiteral("12345")); 0170 QVERIFY(incidence->customProperties().isEmpty()); 0171 } 0172 0173 void ICalFormatTest::testCuType() 0174 { 0175 ICalFormat format; 0176 const QDate currentDate = QDate::currentDate(); 0177 Event::Ptr event(new Event()); 0178 event->setUid(QStringLiteral("12345")); 0179 event->setDtStart(QDateTime(currentDate, {})); 0180 event->setDtEnd(QDateTime(currentDate.addDays(1), {})); 0181 event->setAllDay(true); 0182 0183 Attendee attendee(QStringLiteral("fred"), QStringLiteral("fred@flintstone.com")); 0184 attendee.setCuType(Attendee::Resource); 0185 0186 event->addAttendee(attendee); 0187 0188 const QString serialized = format.toString(event.staticCast<Incidence>()); 0189 0190 // test fromString(QString) 0191 const QString serializedCalendar = QLatin1String("BEGIN:VCALENDAR\nPRODID:-//K Desktop Environment//NONSGML libkcal 3.2//EN\nVERSION:2.0\n") + serialized 0192 + QLatin1String("\nEND:VCALENDAR"); 0193 0194 Incidence::Ptr event2 = format.fromString(serializedCalendar); 0195 QVERIFY(event2->attendeeCount() == 1); 0196 Attendee attendee2 = event2->attendees()[0]; 0197 QVERIFY(attendee2.cuType() == attendee.cuType()); 0198 QVERIFY(attendee2.name() == attendee.name()); 0199 QVERIFY(attendee2.email() == attendee.email()); 0200 } 0201 0202 void ICalFormatTest::testAlarm() 0203 { 0204 ICalFormat format; 0205 0206 Event::Ptr event(new Event); 0207 event->setDtStart(QDate(2017, 03, 24).startOfDay()); 0208 Alarm::Ptr alarm = event->newAlarm(); 0209 alarm->setType(Alarm::Display); 0210 alarm->setStartOffset(Duration(0)); 0211 0212 const QString serialized = QLatin1String("BEGIN:VCALENDAR\nPRODID:-//K Desktop Environment//NONSGML libkcal 3.2//EN\nVERSION:2.0\n") 0213 + format.toString(event.staticCast<Incidence>()) + QLatin1String("\nEND:VCALENDAR"); 0214 0215 Incidence::Ptr event2 = format.fromString(serialized); 0216 Alarm::Ptr alarm2 = event2->alarms()[0]; 0217 QCOMPARE(*alarm, *alarm2); 0218 } 0219 0220 void ICalFormatTest::testDateTimeSerialization_data() 0221 { 0222 QTest::addColumn<QDateTime>("dtStart"); 0223 QTest::addColumn<QByteArray>("dtStartData"); 0224 0225 QTest::newRow("UTC time spec") << QDateTime(QDate(2021, 4, 9), QTime(12, 00), QTimeZone::UTC) << QByteArray("DTSTART:20210409T120000Z"); 0226 QTest::newRow("UTC time zone") 0227 << QDateTime(QDate(2021, 4, 9), QTime(12, 00), QTimeZone::utc()) 0228 << QByteArray("DTSTART:20210409T120000Z"); 0229 QTest::newRow("named time zone") 0230 << QDateTime(QDate(2021, 4, 9), QTime(14, 00), QTimeZone("Europe/Paris")) 0231 << QByteArray("DTSTART;TZID=Europe/Paris:20210409T140000"); 0232 } 0233 0234 void ICalFormatTest::testDateTimeSerialization() 0235 { 0236 QFETCH(QDateTime, dtStart); 0237 QFETCH(QByteArray, dtStartData); 0238 0239 Incidence::Ptr event(new Event); 0240 QVERIFY(event); 0241 event->setDtStart(dtStart); 0242 QCOMPARE(event->dtStart(), dtStart); 0243 0244 ICalFormat format; 0245 const QByteArray output = format.toRawString(event); 0246 const QList<QByteArray> lines = output.split('\n'); 0247 for (const QByteArray &line: lines) { 0248 if (line.startsWith(QByteArray("DTSTART"))) { 0249 QCOMPARE(line.chopped(1), dtStartData); 0250 break; 0251 } 0252 } 0253 } 0254 0255 void ICalFormatTest::testRDate() 0256 { 0257 ICalFormat format; 0258 0259 const QString serializedCalendar = QLatin1String( 0260 "BEGIN:VCALENDAR\n" 0261 "VERSION:2.0\n" 0262 "PRODID:-//Lotus Development Corporation//NONSGML Notes 9.0.1//EN_C\n" 0263 "METHOD:PUBLISH\n" 0264 "BEGIN:VEVENT\n" 0265 "DTSTART:20210630T100000Z\n" 0266 "DTEND:20210630T110000Z\n" 0267 "TRANSP:OPAQUE\n" 0268 "RDATE;VALUE=PERIOD:20210630T100000Z/20210630T110000Z\n" 0269 " ,20210825T100000Z/20210825T110000Z,20211027T100000Z/20211027T110000Z\n" 0270 " ,20211215T110000Z/PT2H\n" 0271 "LAST-MODIFIED:20210601T094627Z\n" 0272 "DTSTAMP:20210601T092939Z\n" 0273 "UID:5FC21473F5CC80CCC12586E70033ED9C-Lotus_Notes_Generated\n" 0274 "END:VEVENT\n" 0275 "END:VCALENDAR\n"); 0276 MemoryCalendar::Ptr calendar(new MemoryCalendar(QTimeZone::utc())); 0277 QVERIFY(format.fromString(calendar, serializedCalendar)); 0278 const QString uid = QString::fromLatin1("5FC21473F5CC80CCC12586E70033ED9C-Lotus_Notes_Generated"); 0279 Incidence::Ptr event = calendar->incidence(uid); 0280 QVERIFY(event); 0281 QVERIFY(event->recurs()); 0282 0283 const QDateTime ev1(QDate(2021, 6, 30), QTime(10, 0), QTimeZone::UTC); 0284 const QDateTime ev2(QDate(2021, 8, 25), QTime(10, 0), QTimeZone::UTC); 0285 const QDateTime ev3(QDate(2021, 10, 27), QTime(10, 0), QTimeZone::UTC); 0286 const QDateTime ev4(QDate(2021, 12, 15), QTime(11, 0), QTimeZone::UTC); 0287 QCOMPARE(event->recurrence()->rDateTimes(), 0288 QList<QDateTime>() << ev1 << ev2 << ev3 << ev4); 0289 0290 OccurrenceIterator it(*calendar, QDateTime(QDate(2021, 6, 1), QTime(0, 0)), 0291 QDateTime(QDate(2021, 12, 31), QTime(0, 0))); 0292 QVERIFY(it.hasNext()); 0293 it.next(); 0294 QCOMPARE(it.occurrenceStartDate(), ev1); 0295 QCOMPARE(it.occurrenceEndDate(), ev1.addSecs(3600)); 0296 QVERIFY(it.hasNext()); 0297 it.next(); 0298 QCOMPARE(it.occurrenceStartDate(), ev2); 0299 QCOMPARE(it.occurrenceEndDate(), ev2.addSecs(3600)); 0300 QVERIFY(it.hasNext()); 0301 it.next(); 0302 QCOMPARE(it.occurrenceStartDate(), ev3); 0303 QCOMPARE(it.occurrenceEndDate(), ev3.addSecs(3600)); 0304 QVERIFY(it.hasNext()); 0305 it.next(); 0306 QCOMPARE(it.occurrenceStartDate(), ev4); 0307 QCOMPARE(it.occurrenceEndDate(), ev4.addSecs(7200)); 0308 0309 const QStringList output = format.toString(calendar).split(QString::fromLatin1("\r\n")); 0310 QVERIFY(output.contains(QString::fromLatin1("RDATE;VALUE=PERIOD:20210630T100000Z/20210630T110000Z"))); 0311 QVERIFY(output.contains(QString::fromLatin1("RDATE;VALUE=PERIOD:20210825T100000Z/20210825T110000Z"))); 0312 QVERIFY(output.contains(QString::fromLatin1("RDATE;VALUE=PERIOD:20211027T100000Z/20211027T110000Z"))); 0313 QVERIFY(output.contains(QString::fromLatin1("RDATE;VALUE=PERIOD:20211215T110000Z/PT2H"))); 0314 } 0315 0316 void ICalFormatTest::testDateTime_data() 0317 { 0318 QTest::addColumn<QByteArray>("dtStartData"); 0319 QTest::addColumn<QDateTime>("dtStart"); 0320 0321 QTest::newRow("clock time") << QByteArray("DTSTART:20191113T130000") << QDateTime(QDate(2019, 11, 13), QTime(13, 00), QTimeZone::LocalTime); 0322 QTest::newRow("date") 0323 << QByteArray("DTSTART;VALUE=DATE:20191113") 0324 << QDate(2019, 11, 13).startOfDay(); 0325 QTest::newRow("UTC time") << QByteArray("DTSTART:20191113T130000Z") << QDateTime(QDate(2019, 11, 13), QTime(13, 00), QTimeZone::UTC); 0326 QTest::newRow("time zone time") 0327 << QByteArray("DTSTART;TZID=Europe/Paris:20191113T130000") 0328 << QDateTime(QDate(2019, 11, 13), QTime(13, 00), QTimeZone("Europe/Paris")); 0329 } 0330 0331 void ICalFormatTest::testDateTime() 0332 { 0333 QFETCH(QByteArray, dtStartData); 0334 QFETCH(QDateTime, dtStart); 0335 0336 // test fromString(QString) 0337 const QByteArray serializedCalendar 0338 = "BEGIN:VCALENDAR\nPRODID:-//K Desktop Environment//NONSGML libkcal 3.2//EN\nVERSION:2.0\nBEGIN:VEVENT\nUID:12345\n" 0339 + dtStartData 0340 + "\nEND:VEVENT\nEND:VCALENDAR"; 0341 0342 ICalFormat format; 0343 Incidence::Ptr event = format.fromString(QString::fromUtf8(serializedCalendar)); 0344 QVERIFY(event); 0345 QCOMPARE(dtStart, event->dtStart()); 0346 } 0347 0348 /** 0349 * If an instance does not have a UID, one will be created for it. 0350 */ 0351 void ICalFormatTest::testUidGeneration() 0352 { 0353 const QString serializedCalendar = QLatin1String( 0354 "BEGIN:VCALENDAR\n" 0355 "VERSION:2.0\n" 0356 "BEGIN:VEVENT\n" 0357 "DTSTAMP:20201103T161340Z\n" 0358 "SUMMARY:test\n" 0359 "END:VEVENT\n" 0360 "END:VCALENDAR"); 0361 auto calendar = MemoryCalendar::Ptr(new MemoryCalendar(QTimeZone::utc())); 0362 ICalFormat format; 0363 QVERIFY(format.fromString(calendar, serializedCalendar)); 0364 const auto events = calendar->events(); 0365 QCOMPARE(events.count(), 1); 0366 const auto event = events[0]; 0367 QVERIFY( ! event->uid().isEmpty()); 0368 } 0369 0370 /** 0371 * Generated UIDs do not depend on the order of properties. 0372 */ 0373 void ICalFormatTest::testUidGenerationStability() 0374 { 0375 ICalFormat format; 0376 0377 const QString serializedCalendar1 = QLatin1String( 0378 "BEGIN:VCALENDAR\n" 0379 "VERSION:2.0\n" 0380 "BEGIN:VEVENT\n" 0381 "DTSTAMP:20201103T161340Z\n" 0382 "SUMMARY:test\n" 0383 "END:VEVENT\n" 0384 "END:VCALENDAR"); 0385 auto calendar1 = MemoryCalendar::Ptr(new MemoryCalendar(QTimeZone::utc())); 0386 QVERIFY(format.fromString(calendar1, serializedCalendar1)); 0387 const auto events1 = calendar1->events(); 0388 QCOMPARE(events1.count(), 1); 0389 0390 const QString serializedCalendar2 = QLatin1String( 0391 "BEGIN:VCALENDAR\n" 0392 "VERSION:2.0\n" 0393 "BEGIN:VEVENT\n" 0394 "SUMMARY:test\n" 0395 "DTSTAMP:20201103T161340Z\n" // Reordered. 0396 "END:VEVENT\n" 0397 "END:VCALENDAR"); 0398 auto calendar2 = MemoryCalendar::Ptr(new MemoryCalendar(QTimeZone::utc())); 0399 QVERIFY(format.fromString(calendar2, serializedCalendar2)); 0400 const auto events2 = calendar2->events(); 0401 QCOMPARE(events2.count(), 1); 0402 0403 const auto event1 = events1[0]; 0404 const auto event2 = events2[0]; 0405 QCOMPARE(event1->uid(), event2->uid()); 0406 } 0407 0408 /** 0409 * Generated UIDs depend on property names and values. 0410 */ 0411 void ICalFormatTest::testUidGenerationUniqueness() 0412 { 0413 ICalFormat format; 0414 0415 const QString serializedCalendar1 = QLatin1String( 0416 "BEGIN:VCALENDAR\n" 0417 "VERSION:2.0\n" 0418 "BEGIN:VEVENT\n" 0419 "DTSTAMP:20201103T161340Z\n" 0420 "SUMMARY:test\n" 0421 "END:VEVENT\n" 0422 "END:VCALENDAR"); 0423 auto calendar1 = MemoryCalendar::Ptr(new MemoryCalendar(QTimeZone::utc())); 0424 QVERIFY(format.fromString(calendar1, serializedCalendar1)); 0425 const auto events1 = calendar1->events(); 0426 QCOMPARE(events1.count(), 1); 0427 0428 const QString serializedCalendar2 = QLatin1String( 0429 "BEGIN:VCALENDAR\n" 0430 "VERSION:2.0\n" 0431 "BEGIN:VEVENT\n" 0432 "DTSTART:20201103T161340Z\n" // Property name change. 0433 "SUMMARY:test\n" 0434 "END:VEVENT\n" 0435 "END:VCALENDAR"); 0436 auto calendar2 = MemoryCalendar::Ptr(new MemoryCalendar(QTimeZone::utc())); 0437 QVERIFY(format.fromString(calendar2, serializedCalendar2)); 0438 const auto events2 = calendar2->events(); 0439 QCOMPARE(events2.count(), 1); 0440 0441 const QString serializedCalendar3 = QLatin1String( 0442 "BEGIN:VCALENDAR\n" 0443 "VERSION:2.0\n" 0444 "BEGIN:VEVENT\n" 0445 "DTSTAMP:20201103T161341Z\n" // Property value changed. 0446 "SUMMARY:test\n" 0447 "END:VEVENT\n" 0448 "END:VCALENDAR"); 0449 auto calendar3 = MemoryCalendar::Ptr(new MemoryCalendar(QTimeZone::utc())); 0450 QVERIFY(format.fromString(calendar3, serializedCalendar3)); 0451 const auto events3 = calendar3->events(); 0452 QCOMPARE(events3.count(), 1); 0453 0454 const auto event1 = events1[0]; 0455 const auto event2 = events2[0]; 0456 const auto event3 = events3[0]; 0457 QVERIFY(event1->uid() != event2->uid()); 0458 QVERIFY(event1->uid() != event3->uid()); 0459 QVERIFY(event2->uid() != event3->uid()); 0460 } 0461 0462 void ICalFormatTest::testIcalFormat() 0463 { 0464 ICalFormat format; 0465 auto duration = format.durationFromString(QStringLiteral("PT2H")); 0466 QVERIFY(!duration.isNull()); 0467 QCOMPARE(duration.asSeconds(), 7200); 0468 QCOMPARE(format.toString(duration), QLatin1String("PT2H")); 0469 } 0470 0471 void ICalFormatTest::testNonTextCustomProperties() 0472 { 0473 const auto input = QLatin1String( 0474 "BEGIN:VCALENDAR\n" 0475 "VERSION:2.0\n" 0476 "BEGIN:VEVENT\n" 0477 "X-APPLE-TRAVEL-START;ROUTING=CAR;VALUE=URI;X-ADDRESS=Bingerdenallee 1\\n\n" 0478 " 6921 JN Duiven\\nNederland;X-TITLE=Home:\n" 0479 "X-APPLE-TRAVEL-DURATION;VALUE=DURATION:PT45M\n" 0480 "X-APPLE-STRUCTURED-LOCATION;VALUE=URI;X-ADDRESS=Olympus 1\\n3524 WB Utre\n" 0481 " cht\\nThe Netherlands;X-APPLE-RADIUS=49.91307222863458;X-TITLE=Olympus 1\n" 0482 " :geo:52.063921,5.128511\n" 0483 "BEGIN:VALARM\n" 0484 "TRIGGER;X-APPLE-RELATED-TRAVEL=-PT30M:-PT1H15M\n" 0485 "END:VALARM\n" 0486 "END:VEVENT\n" 0487 "END:VCALENDAR\n"); 0488 ICalFormat format; 0489 MemoryCalendar::Ptr cal(new MemoryCalendar(QTimeZone::utc())); 0490 QVERIFY(format.fromString(cal, input)); 0491 const auto events = cal->events(); 0492 QCOMPARE(events.size(), 1); 0493 0494 const auto event = events[0]; 0495 QCOMPARE(event->nonKDECustomProperty("X-APPLE-TRAVEL-DURATION"), QLatin1String("PT45M")); 0496 QCOMPARE(event->nonKDECustomProperty("X-APPLE-TRAVEL-START"), QString()); 0497 QCOMPARE(event->nonKDECustomProperty("X-APPLE-STRUCTURED-LOCATION"), QLatin1String("geo:52.063921,5.128511")); 0498 } 0499 0500 void ICalFormatTest::testAllDaySchedulingMessage() 0501 { 0502 auto event = KCalendarCore::Event::Ptr::create(); 0503 event->setSummary(QStringLiteral("All Day Event")); 0504 event->setDtStart(QDateTime(QDate(2023, 10, 13), QTime(0, 0, 0), QTimeZone("Europe/Prague"))); 0505 event->setDtEnd(QDateTime(QDate(2023, 10, 15), QTime(0, 0, 0), QTimeZone("Europe/Prague"))); 0506 event->setOrganizer(Person(QStringLiteral("Dan"), QStringLiteral("dvratil@example.com"))); 0507 event->addAttendee(Attendee(QStringLiteral("Konqi"), QStringLiteral("konqi@example.com"))); 0508 event->setAllDay(true); 0509 0510 ICalFormat format; 0511 auto calendar = MemoryCalendar::Ptr::create(QTimeZone::utc()); 0512 const auto itipString = format.createScheduleMessage(event, KCalendarCore::iTIPRequest); 0513 QVERIFY(!itipString.isEmpty()); 0514 0515 auto scheduleMsg = format.parseScheduleMessage(calendar, itipString); 0516 QVERIFY(scheduleMsg->error().isEmpty()); 0517 0518 auto parsedEvent = scheduleMsg->event().staticCast<KCalendarCore::Event>(); 0519 QVERIFY(parsedEvent); 0520 QCOMPARE(parsedEvent->dtStart().date(), event->dtStart().date()); 0521 QCOMPARE(parsedEvent->dtEnd().date(), event->dtEnd().date()); 0522 } 0523 0524 #include "moc_testicalformat.cpp"