File indexing completed on 2024-04-21 03:52:42
0001 /* 0002 This file is part of the kcalcore library. 0003 0004 SPDX-FileCopyrightText: 2011 Sérgio Martins <iamsergio@gmail.com> 0005 0006 SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 #include "testrecurtodo.h" 0009 #include "todo.h" 0010 0011 #include <QDebug> 0012 #include <QTest> 0013 0014 QTEST_MAIN(RecurTodoTest) 0015 0016 using namespace KCalendarCore; 0017 0018 void RecurTodoTest::setTimeZone(const char *zonename) 0019 { 0020 QVERIFY(QTimeZone(zonename).isValid()); 0021 qputenv("TZ", zonename); 0022 const QDateTime currentDateTime = QDateTime::currentDateTime(); 0023 QVERIFY(currentDateTime.timeZone().isValid()); 0024 QCOMPARE(currentDateTime.timeZoneAbbreviation(), QString::fromLatin1(zonename)); 0025 } 0026 0027 void RecurTodoTest::testAllDay() 0028 { 0029 setTimeZone("UTC"); 0030 const QDate currentDate = QDate::currentDate(); 0031 const QDateTime currentUtcDateTime = QDateTime::currentDateTimeUtc(); 0032 0033 const QDate dueDate(QDate::currentDate()); 0034 QCOMPARE(currentDate, dueDate); 0035 QCOMPARE(currentDate, currentUtcDateTime.date()); 0036 0037 Todo todo; 0038 todo.setDtStart(QDateTime(dueDate.addDays(-1), {})); 0039 todo.setDtDue(QDateTime(dueDate, {})); 0040 todo.setSummary(QStringLiteral("All day event")); 0041 todo.setAllDay(true); 0042 0043 QCOMPARE(todo.dtStart().daysTo(todo.dtDue()), 1); 0044 QVERIFY(!todo.recurs()); 0045 0046 Recurrence *recurrence = todo.recurrence(); 0047 recurrence->unsetRecurs(); 0048 recurrence->setDaily(1); 0049 QCOMPARE(todo.dtDue(), QDateTime(dueDate, {})); 0050 QCOMPARE(todo.percentComplete(), 0); 0051 QVERIFY(todo.recurs()); // Previously it did not recur 0052 todo.setCompleted(currentUtcDateTime); 0053 QVERIFY(todo.recurs()); 0054 QCOMPARE(todo.percentComplete(), 0); // It is still not done 0055 const QDate newStartDate = todo.dtStart().date(); 0056 const QDate newDueDate = todo.dtDue().date(); 0057 QCOMPARE(newStartDate, currentDate); 0058 QCOMPARE(newStartDate.daysTo(newDueDate), 1); 0059 0060 todo.setCompleted(currentUtcDateTime); 0061 0062 QCOMPARE(newDueDate, currentDate.addDays(1)); 0063 QCOMPARE(todo.dtDue(true /*first occurrence*/).date(), dueDate); 0064 } 0065 0066 void RecurTodoTest::testRecurrenceStart() 0067 { 0068 setTimeZone("UTC"); 0069 const QDateTime currentDateTime = QDateTime::currentDateTime(); 0070 const QDate currentDate = currentDateTime.date(); 0071 const QTime currentTimeWithMS = currentDateTime.time(); 0072 0073 const QDate fourDaysAgo(currentDate.addDays(-4)); 0074 const QDate treeDaysAgo(currentDate.addDays(-3)); 0075 const QTime currentTime(currentTimeWithMS.hour(), currentTimeWithMS.minute(), currentTimeWithMS.second()); 0076 0077 Todo todo; 0078 Recurrence *recurrence = todo.recurrence(); 0079 recurrence->unsetRecurs(); 0080 recurrence->setDaily(1); 0081 todo.setDtStart(QDateTime(fourDaysAgo, currentTime)); 0082 const QDateTime originalDtDue(treeDaysAgo, currentTime); 0083 todo.setDtDue(originalDtDue); 0084 todo.setSummary(QStringLiteral("Not an all day event")); 0085 QVERIFY(!todo.allDay()); 0086 QVERIFY(recurrence->startDateTime().isValid()); 0087 } 0088 0089 void RecurTodoTest::testNonAllDay() 0090 { 0091 setTimeZone("UTC"); 0092 const QDateTime currentDateTime = QDateTime::currentDateTime(); 0093 const QDate currentDate = currentDateTime.date(); 0094 const QTime currentTimeWithMS = currentDateTime.time(); 0095 0096 const QDate fourDaysAgo(currentDate.addDays(-4)); 0097 const QDate treeDaysAgo(currentDate.addDays(-3)); 0098 const QTime currentTime(currentTimeWithMS.hour(), currentTimeWithMS.minute(), currentTimeWithMS.second()); 0099 0100 Todo todo; 0101 todo.setDtStart(QDateTime(fourDaysAgo, currentTime)); 0102 const QDateTime originalDtDue(treeDaysAgo, currentTime); 0103 todo.setDtDue(originalDtDue); 0104 todo.setSummary(QStringLiteral("Not an all day event")); 0105 QVERIFY(!todo.allDay()); 0106 Recurrence *recurrence = todo.recurrence(); 0107 recurrence->unsetRecurs(); 0108 recurrence->setDaily(1); 0109 QVERIFY(recurrence->startDateTime().isValid()); 0110 QCOMPARE(todo.dtDue(), originalDtDue); 0111 todo.setCompleted(QDateTime::currentDateTimeUtc()); 0112 QVERIFY(todo.recurs()); 0113 QVERIFY(todo.percentComplete() == 0); 0114 0115 const bool equal = todo.dtStart() == QDateTime(currentDate, currentTime, todo.dtStart().timeZone()).addDays(1); 0116 if (!equal) { 0117 qDebug() << "Test Failed. dtDue = " << todo.dtDue().toString() << "OriginalDtDue:" << originalDtDue.toString() 0118 << "QDateTime:" << QDateTime(currentDate, currentTime, todo.dtDue().timeZone()).addDays(1).toString(); 0119 } 0120 0121 QVERIFY(equal); 0122 0123 todo.setCompleted(QDateTime::currentDateTimeUtc()); 0124 QCOMPARE(todo.dtStart(), QDateTime(currentDate, currentTime, todo.dtStart().timeZone()).addDays(2)); 0125 QCOMPARE(todo.dtDue(true /*first occurrence*/), QDateTime(treeDaysAgo, currentTime)); 0126 } 0127 0128 void RecurTodoTest::testIsAllDay() 0129 { 0130 KCalendarCore::Todo::Ptr todo(new KCalendarCore::Todo()); 0131 todo->setUid(QStringLiteral("todo")); 0132 todo->setDtStart(QDateTime(QDate(2013, 03, 10), QTime(10, 0, 0), QTimeZone::UTC)); 0133 todo->setDtDue(QDateTime(QDate(2013, 03, 10), QTime(10, 0, 0), QTimeZone::UTC)); 0134 todo->recurrence()->setDaily(1); 0135 todo->recurrence()->setDuration(2); 0136 QCOMPARE(todo->allDay(), false); 0137 QCOMPARE(todo->recurrence()->allDay(), false); 0138 0139 KCalendarCore::Todo::Ptr allDay(new KCalendarCore::Todo()); 0140 allDay->setUid(QStringLiteral("todo")); 0141 allDay->setDtStart(QDateTime(QDate(2013, 03, 10), {}, QTimeZone::UTC)); 0142 allDay->setDtDue(QDateTime(QDate(2013, 03, 10), {}, QTimeZone::UTC)); 0143 allDay->setAllDay(true); 0144 allDay->recurrence()->setDaily(1); 0145 allDay->recurrence()->setDuration(2); 0146 QCOMPARE(allDay->allDay(), true); 0147 QCOMPARE(allDay->recurrence()->allDay(), true); 0148 } 0149 0150 void RecurTodoTest::testHasDueDate() 0151 { 0152 KCalendarCore::Todo::Ptr todo(new KCalendarCore::Todo()); 0153 todo->setUid(QStringLiteral("todo")); 0154 todo->setDtStart(QDateTime(QDate(2013, 03, 10), QTime(10, 0, 0), QTimeZone::UTC)); 0155 todo->recurrence()->setDaily(1); 0156 todo->recurrence()->setDuration(2); 0157 QVERIFY(!todo->hasDueDate()); 0158 } 0159 0160 void RecurTodoTest::testRecurTodo_data() 0161 { 0162 QTest::addColumn<QDateTime>("dtstart"); 0163 QTest::addColumn<QDateTime>("dtdue"); 0164 0165 // Can't use QDateTime::currentDateTimeUtc() due to milliseconds mismatching 0166 const QDateTime today = QDateTime::fromSecsSinceEpoch(QDateTime::currentSecsSinceEpoch(), QTimeZone::UTC); 0167 const QDateTime tomorrow = today.addDays(1); 0168 const QDateTime invalid; 0169 0170 QTest::newRow("valid dtstart") << today << invalid; 0171 QTest::newRow("valid dtstart and dtdue") << today << tomorrow; 0172 QTest::newRow("valid dtdue") << invalid << today; 0173 } 0174 0175 void RecurTodoTest::testRecurTodo() 0176 { 0177 QFETCH(QDateTime, dtstart); 0178 QFETCH(QDateTime, dtdue); 0179 0180 KCalendarCore::Todo::Ptr todo(new KCalendarCore::Todo()); 0181 todo->setUid(QStringLiteral("todo")); 0182 todo->setDtStart(dtstart); 0183 todo->setDtDue(dtdue); 0184 todo->recurrence()->setDaily(1); 0185 0186 const bool legacyMode = !dtstart.isValid(); 0187 QCOMPARE(todo->percentComplete(), 0); 0188 0189 // Recur it 0190 todo->setCompleted(QDateTime::currentDateTimeUtc()); 0191 QCOMPARE(todo->percentComplete(), 0); 0192 0193 if (legacyMode) { 0194 QVERIFY(todo->dtDue().isValid()); 0195 QVERIFY(!todo->dtStart().isValid()); 0196 QCOMPARE(todo->dtDue(), dtdue.addDays(1)); 0197 0198 QCOMPARE(todo->dtDue(/**first=*/true), dtdue); 0199 } else { 0200 QVERIFY(todo->dtStart().isValid()); 0201 QVERIFY(!(todo->dtDue().isValid() ^ dtdue.isValid())); 0202 QCOMPARE(todo->dtStart(), dtstart.addDays(1)); 0203 0204 if (dtdue.isValid()) { 0205 const int delta = dtstart.daysTo(dtdue); 0206 QCOMPARE(todo->dtStart().daysTo(todo->dtDue()), delta); 0207 } 0208 0209 QCOMPARE(todo->dtStart(/**first=*/true), dtstart); 0210 } 0211 } 0212 0213 void RecurTodoTest::testDtStart() 0214 { 0215 QDateTime start(QDate(2013, 03, 10), QTime(10, 0, 0), QTimeZone::UTC); 0216 KCalendarCore::Todo::Ptr todo(new KCalendarCore::Todo()); 0217 todo->setUid(QStringLiteral("todo")); 0218 todo->setDtStart(start); 0219 todo->recurrence()->setDaily(1); 0220 todo->recurrence()->setDuration(2); 0221 QCOMPARE(todo->dtStart(), start); 0222 0223 KCalendarCore::Todo::Ptr todoWithDue(new KCalendarCore::Todo()); 0224 todoWithDue->setUid(QStringLiteral("todoWithDue")); 0225 todoWithDue->setDtStart(start); 0226 todoWithDue->setDtDue(QDateTime(start).addSecs(60)); 0227 todoWithDue->recurrence()->setDaily(1); 0228 todoWithDue->recurrence()->setDuration(2); 0229 QCOMPARE(todoWithDue->dtStart(), start); 0230 } 0231 0232 void RecurTodoTest::testRecurrenceBasedOnDtStart() 0233 { 0234 const QDateTime dtstart(QDate(2013, 03, 10), QTime(10, 0, 0), QTimeZone::UTC); 0235 const QDateTime dtdue(QDate(2013, 03, 10), QTime(11, 0, 0), QTimeZone::UTC); 0236 0237 KCalendarCore::Todo::Ptr todo(new KCalendarCore::Todo()); 0238 todo->setUid(QStringLiteral("todo")); 0239 todo->setDtStart(dtstart); 0240 todo->setDtDue(dtdue); 0241 todo->recurrence()->setDaily(1); 0242 todo->recurrence()->setDuration(3); 0243 0244 QCOMPARE(todo->recurrence()->getNextDateTime(dtstart.addMSecs(-1)), dtstart); 0245 QCOMPARE(todo->recurrence()->getNextDateTime(dtstart), dtstart.addDays(1)); 0246 QCOMPARE(todo->recurrence()->getNextDateTime(dtstart.addDays(1)), dtstart.addDays(2)); 0247 QCOMPARE(todo->recurrence()->getNextDateTime(dtstart.addDays(2)), QDateTime()); 0248 } 0249 0250 // For backwards compatibility only 0251 void RecurTodoTest::testRecurrenceBasedOnDue() 0252 { 0253 const QDateTime dtdue(QDate(2013, 03, 10), QTime(11, 0, 0), QTimeZone::UTC); 0254 0255 KCalendarCore::Todo::Ptr todo(new KCalendarCore::Todo()); 0256 todo->setUid(QStringLiteral("todo")); 0257 todo->setDtDue(dtdue); 0258 todo->recurrence()->setDaily(1); 0259 todo->recurrence()->setDuration(3); 0260 0261 QCOMPARE(todo->recurrence()->getNextDateTime(dtdue.addMSecs(-1)), dtdue); 0262 QCOMPARE(todo->recurrence()->getNextDateTime(dtdue), dtdue.addDays(1)); 0263 QCOMPARE(todo->recurrence()->getNextDateTime(dtdue.addDays(1)), dtdue.addDays(2)); 0264 QCOMPARE(todo->recurrence()->getNextDateTime(dtdue.addDays(2)), QDateTime()); 0265 } 0266 0267 /** Test that occurrences specified by a recurrence rule are eliminated by 0268 * exception dates. 0269 */ 0270 void RecurTodoTest::testRecurrenceExdates() 0271 { 0272 const QDateTime dtstart(QDate(2013, 03, 10), QTime(10, 0, 0), QTimeZone::UTC); 0273 const QDateTime dtdue(QDate(2013, 03, 10), QTime(11, 0, 0), QTimeZone::UTC); 0274 0275 KCalendarCore::Todo::Ptr todo(new KCalendarCore::Todo()); 0276 todo->setUid(QStringLiteral("todo")); 0277 todo->setDtStart(dtstart); 0278 todo->setDtDue(dtdue); 0279 todo->recurrence()->setDaily(1); 0280 todo->recurrence()->setDuration(3); 0281 0282 // Test for boundary errors. 0283 todo->recurrence()->addExDateTime(dtstart); 0284 todo->recurrence()->addExDateTime(dtstart.addDays(2)); 0285 0286 QCOMPARE(todo->recurrence()->getNextDateTime(dtstart.addMSecs(-1)), dtstart.addDays(1)); 0287 QCOMPARE(todo->recurrence()->getNextDateTime(dtstart.addDays(1)), QDateTime()); 0288 } 0289 0290 #include "moc_testrecurtodo.cpp"